[jakarta-taglibs-standard] 01/02: Imported Upstream 1.1.2

Miguel Landaeta nomadium at moszumanska.debian.org
Sun Mar 15 04:56:15 UTC 2015


This is an automated email from the git hooks/post-receive script.

nomadium pushed a commit to branch master
in repository jakarta-taglibs-standard.

commit 8bb404b42ba4434629acdf7b30938c0a0df4d69c
Author: Miguel Landaeta <nomadium at debian.org>
Date:   Sat Mar 14 19:19:10 2015 -0300

    Imported Upstream 1.1.2
---
 LICENSE                                            |  201 ++
 NOTICE                                             |    2 +
 common.properties                                  |  104 +
 standard/.#build.xml.1.43                          |  490 ++++
 standard/README_bin.txt                            |  138 ++
 standard/README_src.txt                            |  344 +++
 standard/build-tests.xml                           |  393 ++++
 standard/build.xml                                 |  488 ++++
 standard/build_sample_standard.properties          |   80 +
 standard/conf/c-1_0-rt.tld                         |  393 ++++
 standard/conf/c-1_0.tld                            |  416 ++++
 standard/conf/c.tld                                |  563 +++++
 standard/conf/fmt-1_0-rt.tld                       |  403 ++++
 standard/conf/fmt-1_0.tld                          |  442 ++++
 standard/conf/fmt.tld                              |  671 ++++++
 standard/conf/fn.tld                               |  207 ++
 standard/conf/permittedTaglibs.tld                 |   34 +
 standard/conf/scriptfree.tld                       |   51 +
 standard/conf/sql-1_0-rt.tld                       |  188 ++
 standard/conf/sql-1_0.tld                          |  213 ++
 standard/conf/sql.tld                              |  289 +++
 standard/conf/x-1_0-rt.tld                         |  256 +++
 standard/conf/x-1_0.tld                            |  273 +++
 standard/conf/x.tld                                |  448 ++++
 standard/doc/conf/web.xml                          |   18 +
 standard/doc/web/GettingStarted.html               |  343 +++
 standard/doc/web/ReleaseNotes.html                 |  750 ++++++
 standard/doc/web/index.html                        |   83 +
 .../taglibs/standard/examples/beans/Address.java   |  162 ++
 .../taglibs/standard/examples/beans/Customer.java  |  221 ++
 .../taglibs/standard/examples/beans/Customers.java |  101 +
 .../taglibs/standard/examples/i18n/Resources.java  |   23 +
 .../standard/examples/i18n/Resources_de.java       |   23 +
 .../standard/examples/i18n/Resources_fr.java       |   23 +
 .../standard/examples/i18n/Resources_it.java       |   17 +
 .../taglibs/standard/examples/startup/Init.java    |  147 ++
 .../standard/examples/taglib/CustomerFmtTag.java   |  117 +
 .../standard/examples/taglib/DefaultLocaleTag.java |   42 +
 .../standard/examples/taglib/EscapeHtmlTag.java    |  136 ++
 .../taglibs/standard/examples/taglib/EvenTag.java  |   45 +
 .../taglibs/standard/examples/taglib/FileTag.java  |  120 +
 .../standard/examples/taglib/Functions.java        |   70 +
 .../standard/examples/taglib/LocalesTag.java       |   62 +
 .../examples/taglib/NullAttributeException.java    |   42 +
 .../taglibs/standard/examples/taglib/OddTag.java   |   49 +
 .../standard/examples/taglib/ResourceTag.java      |  139 ++
 .../standard/examples/taglib/UsCustomerTag.java    |   93 +
 .../taglibs/standard/examples/util/IOBean.java     |   59 +
 .../util/ServletResponseWrapperForWriter.java      |   62 +
 .../taglibs/standard/examples/util/Util.java       |   56 +
 standard/examples/web/ShowSource.jsp               |   36 +
 .../examples/web/Templates/ExamplesTemplate.dwt    |   38 +
 .../examples/web/WEB-INF/tlds/jstl-examples.tld    |  165 ++
 standard/examples/web/WEB-INF/web.xml              |   22 +
 standard/examples/web/conditionals/Choose.jsp      |   27 +
 .../examples/web/conditionals/CustomLogicTag.jsp   |   36 +
 .../examples/web/conditionals/FailureLocal.jsp     |   27 +
 standard/examples/web/conditionals/If.jsp          |   19 +
 standard/examples/web/conditionals/index.html      |   59 +
 standard/examples/web/elsupport/Out.jsp            |   34 +
 standard/examples/web/elsupport/Set.jsp            |   33 +
 standard/examples/web/elsupport/Set2.jsp           |   16 +
 standard/examples/web/elsupport/index.html         |   60 +
 standard/examples/web/format/Demo.jsp              |  118 +
 standard/examples/web/format/FormatDateTime.jsp    |   74 +
 .../web/format/FormatDateTimeBrowserLocale.jsp     |   73 +
 standard/examples/web/format/FormatNumber.jsp      |   41 +
 .../web/format/FormatNumberBrowserLocale.jsp       |   52 +
 standard/examples/web/format/GermanLocale.jsp      |   18 +
 .../examples/web/format/GermanUmlautCorrect.jsp    |   20 +
 .../examples/web/format/GermanUmlautIncorrect.jsp  |   18 +
 standard/examples/web/format/ItalianLocale.jsp     |   15 +
 .../examples/web/format/MissingResourceBundle.jsp  |   22 +
 .../examples/web/format/ParametricReplacement.jsp  |   66 +
 standard/examples/web/format/PrefixAttribute.jsp   |   16 +
 standard/examples/web/format/RequestEncoding.jsp   |   18 +
 standard/examples/web/format/UndefinedKey.jsp      |   15 +
 standard/examples/web/format/index.html            |   89 +
 standard/examples/web/functions/EscapeXml.jsp      |   39 +
 standard/examples/web/functions/Length.jsp         |   37 +
 standard/examples/web/functions/Replace.jsp        |   55 +
 standard/examples/web/functions/SplitJoin.jsp      |   87 +
 .../web/functions/StringCapitalization.jsp         |   55 +
 standard/examples/web/functions/StringSubset.jsp   |  183 ++
 .../examples/web/functions/SubstringContained.jsp  |  227 ++
 standard/examples/web/functions/Trim.jsp           |   48 +
 standard/examples/web/functions/index.html         |   90 +
 standard/examples/web/global.css                   |    4 +
 standard/examples/web/images/code.gif              |  Bin 0 -> 292 bytes
 standard/examples/web/images/execute.gif           |  Bin 0 -> 1242 bytes
 standard/examples/web/images/return.gif            |  Bin 0 -> 1231 bytes
 standard/examples/web/import/Absolute.jsp          |   19 +
 standard/examples/web/import/AbsoluteFtp.jsp       |   18 +
 standard/examples/web/import/ContextRelative.jsp   |   20 +
 standard/examples/web/import/Encode.jsp            |   47 +
 .../examples/web/import/EncodeContextRelative.jsp  |   20 +
 standard/examples/web/import/ExposeString.jsp      |   20 +
 .../examples/web/import/ExposeStringRelative.jsp   |   17 +
 standard/examples/web/import/LocalSample.jsp       |   14 +
 standard/examples/web/import/Param.jsp             |   13 +
 standard/examples/web/import/Relative.jsp          |   18 +
 standard/examples/web/import/StartSlash.jsp        |   16 +
 standard/examples/web/import/index.html            |   99 +
 standard/examples/web/import/index.jsp             |   94 +
 standard/examples/web/import/links.html            |   46 +
 standard/examples/web/import/relativeLinks.html    |   10 +
 standard/examples/web/import/session.jsp           |   33 +
 standard/examples/web/index.html                   |  142 ++
 standard/examples/web/iterators/Collaboration.jsp  |   42 +
 standard/examples/web/iterators/DataTypes.jsp      |   40 +
 standard/examples/web/iterators/Extensability.jsp  |   45 +
 standard/examples/web/iterators/ForTokens.jsp      |   25 +
 standard/examples/web/iterators/Simple.jsp         |   18 +
 standard/examples/web/iterators/SimpleRange.jsp    |   16 +
 standard/examples/web/iterators/Status.jsp         |   53 +
 standard/examples/web/iterators/index.html         |   78 +
 standard/examples/web/misc/IteratorTest.jsp        |   60 +
 standard/examples/web/misc/index.html              |   46 +
 standard/examples/web/sql/DriverSetup.jsp          |   22 +
 standard/examples/web/sql/QueryDirect.jsp          |   86 +
 standard/examples/web/sql/QueryIterate.jsp         |  104 +
 standard/examples/web/sql/QueryParam.jsp           |   72 +
 standard/examples/web/sql/Transaction.jsp          |   60 +
 standard/examples/web/sql/Update.jsp               |  115 +
 standard/examples/web/sql/index.jsp                |  100 +
 standard/examples/web/sql/links.html               |   32 +
 standard/examples/web/sql/session.jsp              |   17 +
 .../examples/web/tlv/PermittedTaglibsError.jsp     |   26 +
 standard/examples/web/tlv/PermittedTaglibsOk.jsp   |   30 +
 standard/examples/web/tlv/ScriptFreeError.jsp      |   15 +
 standard/examples/web/tlv/ScriptFreeOk.jsp         |   25 +
 standard/examples/web/tlv/index.html               |   67 +
 standard/examples/web/xml/Filter.jsp               |   33 +
 standard/examples/web/xml/ForEach.jsp              |   83 +
 standard/examples/web/xml/ForEachDoc.xml           |   15 +
 standard/examples/web/xml/If.jsp                   |   42 +
 standard/examples/web/xml/Out.jsp                  |   66 +
 standard/examples/web/xml/Parse.jsp                |   30 +
 standard/examples/web/xml/ParseWithEntities.jsp    |   27 +
 standard/examples/web/xml/Set.jsp                  |   31 +
 standard/examples/web/xml/Transform.jsp            |   58 +
 .../examples/web/xml/TransformWithInclusion.jsp    |   32 +
 standard/examples/web/xml/When.jsp                 |   68 +
 standard/examples/web/xml/games.xml                |   31 +
 standard/examples/web/xml/included.xml             |    3 +
 standard/examples/web/xml/includedStylesheet.xsl   |    8 +
 standard/examples/web/xml/index.html               |   81 +
 .../jsp/jstl/core/ConditionalTagSupport.java       |  158 ++
 .../src/javax/servlet/jsp/jstl/core/Config.java    |  374 +++
 .../src/javax/servlet/jsp/jstl/core/LoopTag.java   |   54 +
 .../javax/servlet/jsp/jstl/core/LoopTagStatus.java |  122 +
 .../servlet/jsp/jstl/core/LoopTagSupport.java      |  592 +++++
 .../javax/servlet/jsp/jstl/fmt/LocaleSupport.java  |  167 ++
 .../servlet/jsp/jstl/fmt/LocalizationContext.java  |  101 +
 .../src/javax/servlet/jsp/jstl/sql/Result.java     |   96 +
 .../src/javax/servlet/jsp/jstl/sql/ResultImpl.java |  172 ++
 .../javax/servlet/jsp/jstl/sql/ResultSupport.java  |   67 +
 .../servlet/jsp/jstl/sql/SQLExecutionTag.java      |   59 +
 .../servlet/jsp/jstl/tlv/PermittedTaglibsTLV.java  |  194 ++
 .../javax/servlet/jsp/jstl/tlv/ScriptFreeTLV.java  |  245 ++
 .../src/org/apache/taglibs/standard/Version.java   |  130 ++
 .../standard/extra/spath/ASCII_CharStream.java     |  377 +++
 .../extra/spath/ASCII_UCodeESC_CharStream.java     |  520 +++++
 .../taglibs/standard/extra/spath/AbsolutePath.java |   49 +
 .../standard/extra/spath/AttributePredicate.java   |   56 +
 .../standard/extra/spath/ParseException.java       |  191 ++
 .../apache/taglibs/standard/extra/spath/Path.java  |   36 +
 .../taglibs/standard/extra/spath/Predicate.java    |   27 +
 .../taglibs/standard/extra/spath/RelativePath.java |   56 +
 .../taglibs/standard/extra/spath/SPathFilter.java  |  272 +++
 .../taglibs/standard/extra/spath/SPathParser.java  |  533 +++++
 .../taglibs/standard/extra/spath/SPathParser.jj    |  297 +++
 .../standard/extra/spath/SPathParserConstants.java |   52 +
 .../extra/spath/SPathParserTokenManager.java       |  683 ++++++
 .../taglibs/standard/extra/spath/SPathTag.java     |   87 +
 .../apache/taglibs/standard/extra/spath/Step.java  |  131 ++
 .../apache/taglibs/standard/extra/spath/Token.java |   81 +
 .../standard/extra/spath/TokenMgrError.java        |  133 ++
 .../apache/taglibs/standard/extra/spath/spath.tld  |   35 +
 .../taglibs/standard/functions/Functions.java      |  234 ++
 .../taglibs/standard/lang/jstl/AndOperator.java    |  103 +
 .../standard/lang/jstl/ArithmeticOperator.java     |   63 +
 .../taglibs/standard/lang/jstl/ArraySuffix.java    |  315 +++
 .../lang/jstl/BeanInfoIndexedProperty.java         |  144 ++
 .../standard/lang/jstl/BeanInfoManager.java        |  382 ++++
 .../standard/lang/jstl/BeanInfoProperty.java       |   77 +
 .../taglibs/standard/lang/jstl/BinaryOperator.java |   81 +
 .../lang/jstl/BinaryOperatorExpression.java        |  138 ++
 .../taglibs/standard/lang/jstl/BooleanLiteral.java |   73 +
 .../taglibs/standard/lang/jstl/Coercions.java      | 1024 +++++++++
 .../taglibs/standard/lang/jstl/ComplexValue.java   |  115 +
 .../taglibs/standard/lang/jstl/Constants.java      |  203 ++
 .../taglibs/standard/lang/jstl/DivideOperator.java |  102 +
 .../taglibs/standard/lang/jstl/ELEvaluator.java    |  473 ++++
 .../taglibs/standard/lang/jstl/ELException.java    |  109 +
 .../apache/taglibs/standard/lang/jstl/ELParser.jj  |  781 +++++++
 .../taglibs/standard/lang/jstl/EmptyOperator.java  |  107 +
 .../taglibs/standard/lang/jstl/EnumeratedMap.java  |  182 ++
 .../standard/lang/jstl/EqualityOperator.java       |   54 +
 .../taglibs/standard/lang/jstl/EqualsOperator.java |   71 +
 .../taglibs/standard/lang/jstl/Evaluator.java      |  167 ++
 .../taglibs/standard/lang/jstl/Expression.java     |   58 +
 .../standard/lang/jstl/ExpressionString.java       |  112 +
 .../standard/lang/jstl/FloatingPointLiteral.java   |   64 +
 .../standard/lang/jstl/FunctionInvocation.java     |  144 ++
 .../standard/lang/jstl/GreaterThanOperator.java    |  118 +
 .../lang/jstl/GreaterThanOrEqualsOperator.java     |  118 +
 .../standard/lang/jstl/ImplicitObjects.java        | 1142 ++++++++++
 .../standard/lang/jstl/IntegerDivideOperator.java  |  102 +
 .../taglibs/standard/lang/jstl/IntegerLiteral.java |   64 +
 .../standard/lang/jstl/JSTLVariableResolver.java   |  108 +
 .../standard/lang/jstl/LessThanOperator.java       |  118 +
 .../lang/jstl/LessThanOrEqualsOperator.java        |  118 +
 .../apache/taglibs/standard/lang/jstl/Literal.java |   72 +
 .../apache/taglibs/standard/lang/jstl/Logger.java  |  776 +++++++
 .../taglibs/standard/lang/jstl/MinusOperator.java  |   83 +
 .../standard/lang/jstl/ModulusOperator.java        |  131 ++
 .../standard/lang/jstl/MultiplyOperator.java       |   83 +
 .../taglibs/standard/lang/jstl/NamedValue.java     |   90 +
 .../standard/lang/jstl/NotEqualsOperator.java      |   71 +
 .../taglibs/standard/lang/jstl/NotOperator.java    |   75 +
 .../taglibs/standard/lang/jstl/NullLiteral.java    |   59 +
 .../taglibs/standard/lang/jstl/OrOperator.java     |  103 +
 .../taglibs/standard/lang/jstl/PlusOperator.java   |   83 +
 .../standard/lang/jstl/PrimitiveObjects.java       |  242 ++
 .../taglibs/standard/lang/jstl/PropertySuffix.java |   95 +
 .../standard/lang/jstl/RelationalOperator.java     |   73 +
 .../standard/lang/jstl/Resources.properties        |  141 ++
 .../standard/lang/jstl/Resources_ja.properties     |  122 +
 .../taglibs/standard/lang/jstl/StringLiteral.java  |  183 ++
 .../standard/lang/jstl/UnaryMinusOperator.java     |  135 ++
 .../taglibs/standard/lang/jstl/UnaryOperator.java  |   58 +
 .../lang/jstl/UnaryOperatorExpression.java         |  132 ++
 .../taglibs/standard/lang/jstl/ValueSuffix.java    |   56 +
 .../standard/lang/jstl/VariableResolver.java       |   51 +
 .../standard/lang/jstl/parser/ELParser.java        | 1204 ++++++++++
 .../lang/jstl/parser/ELParserConstants.java        |  117 +
 .../lang/jstl/parser/ELParserTokenManager.java     | 1041 +++++++++
 .../standard/lang/jstl/parser/ParseException.java  |  192 ++
 .../lang/jstl/parser/SimpleCharStream.java         |  401 ++++
 .../taglibs/standard/lang/jstl/parser/Token.java   |   81 +
 .../standard/lang/jstl/parser/TokenMgrError.java   |  133 ++
 .../taglibs/standard/lang/jstl/test/Bean1.java     |  276 +++
 .../taglibs/standard/lang/jstl/test/Bean2.java     |   62 +
 .../standard/lang/jstl/test/Bean2Editor.java       |   45 +
 .../standard/lang/jstl/test/EvaluationTest.java    |  413 ++++
 .../standard/lang/jstl/test/PageContextImpl.java   |  301 +++
 .../standard/lang/jstl/test/ParserTest.java        |  254 +++
 .../lang/jstl/test/StaticFunctionTests.java        |   96 +
 .../standard/lang/jstl/test/beans/Factory.java     |   63 +
 .../lang/jstl/test/beans/PrivateBean1a.java        |   30 +
 .../lang/jstl/test/beans/PrivateBean2b.java        |   31 +
 .../lang/jstl/test/beans/PrivateBean2c.java        |   31 +
 .../lang/jstl/test/beans/PrivateBean2d.java        |   31 +
 .../standard/lang/jstl/test/beans/PublicBean1.java |   30 +
 .../lang/jstl/test/beans/PublicBean1b.java         |   31 +
 .../lang/jstl/test/beans/PublicBean2a.java         |   31 +
 .../lang/jstl/test/beans/PublicInterface2.java     |   30 +
 .../standard/lang/jstl/test/evaluationTests.txt    | 1056 +++++++++
 .../lang/jstl/test/evaluationTestsOutput.txt       | 2390 ++++++++++++++++++++
 .../standard/lang/jstl/test/parserTests.txt        |  148 ++
 .../standard/lang/jstl/test/parserTestsOutput.txt  |  260 +++
 .../standard/lang/support/ExpressionEvaluator.java |   62 +
 .../lang/support/ExpressionEvaluatorManager.java   |  149 ++
 .../taglibs/standard/resources/Resources.java      |  126 ++
 .../standard/resources/Resources.properties        |  304 +++
 .../standard/resources/Resources_ja.properties     |  297 +++
 .../taglibs/standard/tag/common/core/CatchTag.java |   93 +
 .../standard/tag/common/core/ChooseTag.java        |  101 +
 .../standard/tag/common/core/DeclareTag.java       |   37 +
 .../standard/tag/common/core/ForEachSupport.java   |  400 ++++
 .../standard/tag/common/core/ForTokensSupport.java |   89 +
 .../standard/tag/common/core/ImportSupport.java    |  552 +++++
 .../tag/common/core/NullAttributeException.java    |   42 +
 .../standard/tag/common/core/OtherwiseTag.java     |   37 +
 .../standard/tag/common/core/OutSupport.java       |  204 ++
 .../standard/tag/common/core/ParamParent.java      |   39 +
 .../standard/tag/common/core/ParamSupport.java     |  178 ++
 .../standard/tag/common/core/RedirectSupport.java  |  122 +
 .../standard/tag/common/core/RemoveTag.java        |  102 +
 .../standard/tag/common/core/SetSupport.java       |  210 ++
 .../standard/tag/common/core/UrlSupport.java       |  166 ++
 .../taglibs/standard/tag/common/core/Util.java     |  293 +++
 .../standard/tag/common/core/WhenTagSupport.java   |   71 +
 .../standard/tag/common/fmt/BundleSupport.java     |  328 +++
 .../standard/tag/common/fmt/FormatDateSupport.java |  207 ++
 .../tag/common/fmt/FormatNumberSupport.java        |  338 +++
 .../standard/tag/common/fmt/MessageSupport.java    |  216 ++
 .../standard/tag/common/fmt/ParamSupport.java      |   94 +
 .../standard/tag/common/fmt/ParseDateSupport.java  |  232 ++
 .../tag/common/fmt/ParseNumberSupport.java         |  201 ++
 .../tag/common/fmt/RequestEncodingSupport.java     |  110 +
 .../standard/tag/common/fmt/SetBundleSupport.java  |   97 +
 .../standard/tag/common/fmt/SetLocaleSupport.java  |  463 ++++
 .../tag/common/fmt/SetTimeZoneSupport.java         |  109 +
 .../standard/tag/common/fmt/TimeZoneSupport.java   |  152 ++
 .../standard/tag/common/sql/DataSourceUtil.java    |  142 ++
 .../standard/tag/common/sql/DataSourceWrapper.java |  115 +
 .../tag/common/sql/DateParamTagSupport.java        |  106 +
 .../taglibs/standard/tag/common/sql/DriverTag.java |  137 ++
 .../standard/tag/common/sql/ParamTagSupport.java   |   61 +
 .../standard/tag/common/sql/QueryTagSupport.java   |  299 +++
 .../standard/tag/common/sql/ResultImpl.java        |  172 ++
 .../tag/common/sql/SetDataSourceTagSupport.java    |  129 ++
 .../tag/common/sql/TransactionTagSupport.java      |  206 ++
 .../standard/tag/common/sql/UpdateTagSupport.java  |  258 +++
 .../standard/tag/common/xml/ExprSupport.java       |   86 +
 .../standard/tag/common/xml/ForEachTag.java        |  122 +
 .../taglibs/standard/tag/common/xml/IfTag.java     |   76 +
 .../tag/common/xml/JSTLPrefixResolver.java         |  153 ++
 .../standard/tag/common/xml/JSTLXPathAPI.java      |  303 +++
 .../standard/tag/common/xml/ParamSupport.java      |   82 +
 .../standard/tag/common/xml/ParseSupport.java      |  314 +++
 .../taglibs/standard/tag/common/xml/SetTag.java    |  107 +
 .../standard/tag/common/xml/TransformSupport.java  |  381 ++++
 .../tag/common/xml/UnresolvableException.java      |   45 +
 .../taglibs/standard/tag/common/xml/WhenTag.java   |   76 +
 .../taglibs/standard/tag/common/xml/XPathUtil.java |  887 ++++++++
 .../standard/tag/el/core/ExpressionUtil.java       |   56 +
 .../taglibs/standard/tag/el/core/ForEachTag.java   |  162 ++
 .../taglibs/standard/tag/el/core/ForTokensTag.java |  176 ++
 .../apache/taglibs/standard/tag/el/core/IfTag.java |   92 +
 .../taglibs/standard/tag/el/core/ImportTag.java    |  122 +
 .../taglibs/standard/tag/el/core/OutTag.java       |  118 +
 .../taglibs/standard/tag/el/core/ParamTag.java     |  111 +
 .../taglibs/standard/tag/el/core/RedirectTag.java  |  109 +
 .../taglibs/standard/tag/el/core/SetTag.java       |  129 ++
 .../taglibs/standard/tag/el/core/UrlTag.java       |  110 +
 .../taglibs/standard/tag/el/core/WhenTag.java      |   90 +
 .../taglibs/standard/tag/el/fmt/BundleTag.java     |  111 +
 .../taglibs/standard/tag/el/fmt/FormatDateTag.java |  167 ++
 .../standard/tag/el/fmt/FormatNumberTag.java       |  250 ++
 .../taglibs/standard/tag/el/fmt/MessageTag.java    |  122 +
 .../taglibs/standard/tag/el/fmt/ParamTag.java      |  107 +
 .../taglibs/standard/tag/el/fmt/ParseDateTag.java  |  194 ++
 .../standard/tag/el/fmt/ParseNumberTag.java        |  176 ++
 .../standard/tag/el/fmt/RequestEncodingTag.java    |  106 +
 .../taglibs/standard/tag/el/fmt/SetBundleTag.java  |   99 +
 .../taglibs/standard/tag/el/fmt/SetLocaleTag.java  |  110 +
 .../standard/tag/el/fmt/SetTimeZoneTag.java        |   99 +
 .../taglibs/standard/tag/el/fmt/TimeZoneTag.java   |   99 +
 .../taglibs/standard/tag/el/sql/DateParamTag.java  |   64 +
 .../taglibs/standard/tag/el/sql/ParamTag.java      |   44 +
 .../taglibs/standard/tag/el/sql/QueryTag.java      |  119 +
 .../standard/tag/el/sql/SetDataSourceTag.java      |  102 +
 .../standard/tag/el/sql/TransactionTag.java        |   59 +
 .../taglibs/standard/tag/el/sql/UpdateTag.java     |   60 +
 .../taglibs/standard/tag/el/xml/ExprTag.java       |  115 +
 .../taglibs/standard/tag/el/xml/ParamTag.java      |  107 +
 .../taglibs/standard/tag/el/xml/ParseTag.java      |  126 ++
 .../taglibs/standard/tag/el/xml/TransformTag.java  |  143 ++
 .../taglibs/standard/tag/rt/core/ForEachTag.java   |   70 +
 .../taglibs/standard/tag/rt/core/ForTokensTag.java |   77 +
 .../apache/taglibs/standard/tag/rt/core/IfTag.java |   78 +
 .../taglibs/standard/tag/rt/core/ImportTag.java    |   50 +
 .../taglibs/standard/tag/rt/core/OutTag.java       |   46 +
 .../taglibs/standard/tag/rt/core/ParamTag.java     |   45 +
 .../taglibs/standard/tag/rt/core/RedirectTag.java  |   45 +
 .../taglibs/standard/tag/rt/core/SetTag.java       |   47 +
 .../taglibs/standard/tag/rt/core/UrlTag.java       |   45 +
 .../taglibs/standard/tag/rt/core/WhenTag.java      |   75 +
 .../taglibs/standard/tag/rt/fmt/BundleTag.java     |   44 +
 .../taglibs/standard/tag/rt/fmt/FormatDateTag.java |   66 +
 .../standard/tag/rt/fmt/FormatNumberTag.java       |   92 +
 .../taglibs/standard/tag/rt/fmt/MessageTag.java    |   47 +
 .../taglibs/standard/tag/rt/fmt/ParamTag.java      |   40 +
 .../taglibs/standard/tag/rt/fmt/ParseDateTag.java  |   82 +
 .../standard/tag/rt/fmt/ParseNumberTag.java        |   73 +
 .../standard/tag/rt/fmt/RequestEncodingTag.java    |   39 +
 .../taglibs/standard/tag/rt/fmt/SetBundleTag.java  |   39 +
 .../taglibs/standard/tag/rt/fmt/SetLocaleTag.java  |   44 +
 .../standard/tag/rt/fmt/SetTimeZoneTag.java        |   39 +
 .../taglibs/standard/tag/rt/fmt/TimeZoneTag.java   |   39 +
 .../taglibs/standard/tag/rt/sql/DateParamTag.java  |   36 +
 .../taglibs/standard/tag/rt/sql/ParamTag.java      |   30 +
 .../taglibs/standard/tag/rt/sql/QueryTag.java      |   75 +
 .../standard/tag/rt/sql/SetDataSourceTag.java      |   52 +
 .../standard/tag/rt/sql/TransactionTag.java        |   55 +
 .../taglibs/standard/tag/rt/sql/UpdateTag.java     |   49 +
 .../taglibs/standard/tag/rt/xml/ExprTag.java       |   38 +
 .../taglibs/standard/tag/rt/xml/ParamTag.java      |   45 +
 .../taglibs/standard/tag/rt/xml/ParseTag.java      |   56 +
 .../taglibs/standard/tag/rt/xml/TransformTag.java  |   73 +
 .../apache/taglibs/standard/tei/DeclareTEI.java    |   45 +
 .../apache/taglibs/standard/tei/ForEachTEI.java    |   46 +
 .../org/apache/taglibs/standard/tei/ImportTEI.java |   41 +
 .../src/org/apache/taglibs/standard/tei/Util.java  |   35 +
 .../apache/taglibs/standard/tei/XmlParseTEI.java   |   53 +
 .../taglibs/standard/tei/XmlTransformTEI.java      |   45 +
 .../apache/taglibs/standard/tlv/JstlBaseTLV.java   |  337 +++
 .../apache/taglibs/standard/tlv/JstlCoreTLV.java   |  326 +++
 .../apache/taglibs/standard/tlv/JstlFmtTLV.java    |  255 +++
 .../apache/taglibs/standard/tlv/JstlSqlTLV.java    |  230 ++
 .../apache/taglibs/standard/tlv/JstlXmlTLV.java    |  306 +++
 standard/test/conf/cactus.properties               |    6 +
 .../org/apache/taglibs/standard/TestVersion.java   |   84 +
 .../taglibs/standard/tag/el/core/TestSetTag.java   |   48 +
 .../apache/taglibs/standard/testutil/TestUtil.java |   34 +
 standard/test/web/WEB-INF/web.xml                  |   44 +
 .../taglibs/standard/tag/el/core/TestSetTag.jsp    |    4 +
 standard/xml/intro.xml                             |  172 ++
 401 files changed, 57867 insertions(+)

diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..f49a4e1
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,201 @@
+                                 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.
\ No newline at end of file
diff --git a/NOTICE b/NOTICE
new file mode 100644
index 0000000..3f59805
--- /dev/null
+++ b/NOTICE
@@ -0,0 +1,2 @@
+This product includes software developed by
+The Apache Software Foundation (http://www.apache.org/).
diff --git a/common.properties b/common.properties
new file mode 100644
index 0000000..ab12a13
--- /dev/null
+++ b/common.properties
@@ -0,0 +1,104 @@
+# 
+# TAGLIB NAME 
+# 
+# The taglib name defaults to the subproject's ant.project.name.  
+
+taglib.name = ${ant.project.name}
+taglibs.basedir = ..
+
+# 
+# PROJECT STRUCTURE PROPERTIES 
+# 
+# The following property values reflect the recommended directory structure 
+# for each custom tag library subproject.  You should only need to adjust or 
+# override them if you use a different organization. 
+# 
+#   conf.src                       Library configuration source directory 
+#   doc.src                        Documentation app source directory 
+#   examples.src                   Examples app source directory 
+#   library.src                    Library Java source directory  
+
+conf.src = conf
+doc.src = doc
+examples.src = examples
+library.src = src
+xml.src = xml
+
+#
+# Used to generate HTML for jakarta.apache.org/taglibs web site
+taglibs.xsl = ${taglibs.basedir}/src/doc/stylesheets/taglibs.xsl
+
+#
+# TAGLIB DOC KIT
+#
+# These properties support the generation of the HTML documentation,
+# jar and war mainifest's, and TLD for a taglib using a single XML document
+#
+taglib-doc.dir = ${taglibs.basedir}/src/taglib
+tld11.xsl = ${taglib-doc.dir}/tld11.xsl
+tld12.xsl = ${taglib-doc.dir}/tld12.xsl
+taglib-doc.xsl = ${taglib-doc.dir}/taglib-doc.xsl
+changes-doc.xsl = ${taglib-doc.dir}/changes-doc.xsl
+manifest.xsl = ${taglib-doc.dir}/manifest.xsl
+
+# Override this property from the ant command line when doing a release
+# with the version number of the release, i.e. 1.0B1
+release=UNKNOWN
+
+# 
+# DERIVED PROPERTIES 
+# 
+# These property values are derived from the previously defined values, and 
+# should not normally be overridden from the command line. 
+# 
+#   build.doc                      Target directory for documentation app 
+#   build.examples                 Target directory for examples app 
+#   build.library                  Target directory for tag library 
+#   taglibs.doc                    Destination directory for taglibs distribution docs
+#   dist.doc                       Destination WAR for documentation app 
+#   dist.examples                  Destination WAR for examples app 
+#   dist.library                   Destination JAR for tag library 
+#   dist.tld                       Destination TLD file for tag library  
+build.doc = ${build.dir}/${taglib.name}/${taglib.name}-doc
+build.examples = ${build.dir}/${taglib.name}/${taglib.name}-examples
+build.library = ${build.dir}/${taglib.name}/${taglib.name}
+taglibs.doc = ${dist.dir}/doc/doc/${taglib.name}-doc
+dist.doc = ${dist.dir}/${taglib.name}/${taglib.name}-doc.war
+dist.examples = ${dist.dir}/${taglib.name}/${taglib.name}-examples.war
+dist.library = ${dist.dir}/${taglib.name}
+dist.tld = ${dist.dir}/${taglib.name}/taglibs-${taglib.name}.tld
+examples.tld = ${build.examples}/WEB-INF/taglibs-${taglib.name}.tld
+library.tld = ${build.library}/META-INF/taglib.tld
+release.name = jakarta-taglibs-${taglib.name}-${release}
+release.dir = ${dist.dir}/${release.name}
+
+# 
+# DEFAULT PRE & POST ACTIONS - ALLOWS SUBPROJECTS TO OVERRIDE 
+# 
+
+checkRequirements.pre=default.pre
+checkRequirements.post=default.post
+prepare.pre=default.pre
+prepare.post=default.post
+documentation.pre=default.pre
+documentation.post=default.post
+examples.pre=default.pre
+examples.post=default.post
+compile-examples.pre=default.pre
+compile-examples.post=default.post
+library.pre=default.pre
+library.post=default.post
+main.pre=default.pre
+main.post=default.post
+documentation-dist.pre=default.pre
+documentation-dist.post=default.post
+examples-dist.pre=default.pre
+examples-dist.post=default.post
+library-dist.pre=default.pre
+library-dist.post=default.post
+dist.pre=default.pre
+dist.post=default.post
+release.pre=default.pre
+release.post=default.post
+clean.pre=default.pre
+clean.post=default.post
diff --git a/standard/.#build.xml.1.43 b/standard/.#build.xml.1.43
new file mode 100644
index 0000000..2e1dc0e
--- /dev/null
+++ b/standard/.#build.xml.1.43
@@ -0,0 +1,490 @@
+<project name="standard" default="build" basedir=".">
+
+  <!-- =================================================================== -->
+  <!-- Version Number                                                      -->
+  <!-- =================================================================== -->
+
+  <property name="standard-version" value="1.1.0" />
+  <property name="release.name" value="jakarta-taglibs-standard-${standard-version}" />
+  <property name="release.pre" value="nop" />
+  <property name="release.post" value="nop" />
+
+  <!-- =================================================================== -->
+  <!-- Inherited properties                                                -->
+  <!-- =================================================================== -->
+
+  <property file="build.properties"/>			<!-- Component local -->
+  <property file="../build.properties"/>		<!-- Commons local   -->
+  <property file="${user.home}/build.properties"/>	<!-- User local      -->
+  <property file="../common.properties"/>
+
+  <!-- =================================================================== -->
+  <!-- taglib specific properties                                                -->
+  <!-- =================================================================== -->
+    
+  <property name="taglib.name"    value="standard"/>
+
+  <!--
+        These property values are derived from the previously defined values,
+	and should not normally be overridden from the command line.
+
+        build.library               Target directory for tag library
+        build.examples		    Target directory for examples app
+        build.doc                   Target directory for documentation app
+	dist.library                Destination JAR for tag library
+	dist.examples		    Destination WAR for examples app
+	dist.doc                    Destination WAR for documentation app
+	dist.tld                    Destination TLD file for tag library
+  -->
+
+  <!-- =================================================================== -->
+  <!-- Destination Preparation                                             -->
+  <!-- =================================================================== -->
+
+  <target name="prepare-dependencies">
+
+    <!-- info on build environment -->
+
+    <echo>---------- Environment Information ----------</echo>
+    <echo>java.home: ${java.home}</echo>
+    <echo>ant.java.version: ${ant.java.version}</echo>
+    <echo>debug: ${compile.debug}</echo>
+    <echo>deprecation: ${compile.deprecation}</echo>
+    <echo>optimize: ${optimize.debug}</echo>
+    <echo>---------- Dependencies ---------------------</echo>
+    <echo>servlet24.jar: ${servlet24.jar}</echo>
+    <echo>jsp20.jar: ${jsp20.jar}</echo>
+    <echo>jdbc2_0-stdext.jar: ${jdbc2_0-stdext.jar}</echo>
+    <echo>jaxp-api.jar: ${jaxp-api.jar}</echo>
+    <echo>dom.jar: ${dom.jar}</echo>
+    <echo>sax.jar: ${sax.jar}</echo>
+    <echo>xalan.jar: ${xalan.jar}</echo>
+    <echo>xercesImpl.jar: ${xercesImpl.jar}</echo>
+    <echo>---------- Build directories ----------------</echo>
+    <echo>build.dir: ${build.dir}</echo>
+    <echo>build.library: ${build.library}</echo>
+    <echo>build.examples: ${build.examples}</echo>
+    <echo>build.doc: ${build.doc}</echo>
+    <echo>---------- Distribution directories ---------</echo>
+    <echo>dist.dir: ${dist.dir}</echo>
+    <echo>dist.library: ${dist.library}</echo>
+    <echo>dist.examples: ${dist.examples}</echo>
+    <echo>dist.doc: ${dist.doc}</echo>
+    <!-- <echo>dist.tld: ${dist.tld}</echo> -->
+    <echo>---------------------------------------------</echo>
+    
+    <!-- Check the build/runtime dependencies -->
+
+    <antcall target="requiredJar">
+       <param name="prop" value="servlet24.jar"/>
+       <param name="file" value="${servlet24.jar}"/>
+       <param name="desc" value="Servlet 2.4 API classes"/>
+    </antcall>
+
+    <antcall target="requiredJar">
+       <param name="prop" value="jsp20.jar"/>
+       <param name="file" value="${jsp20.jar}"/>
+       <param name="desc" value="JSP 2.0 API classes"/>
+    </antcall>
+
+    <antcall target="processIfPropSet">
+       <param name="prop" value="jdbc2_0-stdext.jar"/>
+       <param name="task" value="requiredJarIfPropSet"/>
+       <param name="file" value="${jdbc2_0-stdext.jar}"/>
+       <param name="desc" value="Sun JDBC 2.0 API classes"/>
+    </antcall>
+
+    <antcall target="processIfPropSet">
+       <param name="prop" value="jaxp-api.jar"/>
+       <param name="task" value="requiredJarIfPropSet"/>
+       <param name="file" value="${jaxp-api.jar}"/>
+       <param name="desc" value="JAXP 1.2 API classes"/>
+    </antcall>
+
+    <antcall target="processIfPropSet">
+       <param name="prop" value="dom.jar"/>
+       <param name="task" value="requiredJarIfPropSet"/>
+       <param name="file" value="${dom.jar}"/>
+       <param name="desc" value="JAXP 1.2 DOM API classes"/>
+    </antcall>
+
+    <antcall target="processIfPropSet">
+       <param name="prop" value="sax.jar"/>
+       <param name="task" value="requiredJarIfPropSet"/>
+       <param name="file" value="${sax.jar}"/>
+       <param name="desc" value="JAXP 1.2 SAX API classes"/>
+    </antcall>
+
+    <antcall target="processIfPropSet">
+       <param name="prop" value="xalan.jar"/>
+       <param name="task" value="requiredJarIfPropSet"/>
+       <param name="file" value="${xalan.jar}"/>
+       <param name="desc" value="Xalan implementation"/>
+    </antcall>
+
+    <antcall target="processIfPropSet">
+       <param name="prop" value="xercesImpl.jar"/>
+       <param name="task" value="requiredJarIfPropSet"/>
+       <param name="file" value="${xercesImpl.jar}"/>
+       <param name="desc" value="Xerces implementation"/>
+    </antcall>
+    
+  </target>
+
+  <!-- Set up build directories -->
+  <target name="prepare-build" depends="prepare-dependencies">
+    <mkdir dir="${build.dir}"/>
+    <mkdir dir="${build.library}"/>
+    <mkdir dir="${build.library}/META-INF"/>
+    <mkdir dir="${build.library}/classes"/>
+    <mkdir dir="${build.library}/lib"/>
+    <mkdir dir="${build.examples}"/>
+    <mkdir dir="${build.examples}/WEB-INF"/>
+    <mkdir dir="${build.examples}/WEB-INF/classes"/>
+    <mkdir dir="${build.examples}/WEB-INF/lib"/>
+    <mkdir dir="${build.doc}"/>
+    <mkdir dir="${build.doc}/WEB-INF"/>
+  </target>
+
+  <!-- Set up distribution directory -->
+  <target name="prepare-dist" depends="prepare-build">
+    <mkdir dir="${dist.dir}"/>
+    <mkdir dir="${dist.library}"/>
+    <mkdir dir="${dist.library}/lib"/>
+    <mkdir dir="${dist.library}/tld"/>
+    <mkdir dir="${dist.library}/javadoc"/>
+  </target>
+
+  <!-- =================================================================== -->
+  <!-- Build Tag Library Components                                      -->
+  <!-- =================================================================== -->
+
+  <target name="build" depends="library-build, examples-build, documentation-build"/>
+
+  <!-- Build the tag library itself -->
+  <target name="library-build" depends="prepare-build">  
+    
+    <!-- Compile the taglib.
+         Need to override xalan classes if using J2SE 1.4, that's why we
+         use bootclasspath. Works with J2SE 1.3 as well. -->
+<!-- DELETE don't need to specify bootclaspath on a mac
+      bootclasspath="${xalan.jar}:${java.home}/lib/rt.jar"
+-->
+    <javac 
+      srcdir="${library.src}" 
+      destdir="${build.library}/classes"
+      classpath="${servlet24.jar}:${jsp20.jar}:${jdbc2_0-stdext.jar}:${jaxp-api.jar}:${dom.jar}:${sax.jar}"
+      excludes="org/apache/taglibs/standard/lang/jstl/parser/jsp20/* org/apache/taglibs/standard/lang/jpath/** org/apache/taglibs/standard/lang/spel/**"
+      debug="${compile.debug}"
+      deprecation="${compile.deprecation}"
+      optimize="${compile.optimize}"/> 
+      
+    <!-- copy the TLDs in META-INF -->
+    <copy todir="${build.library}/META-INF">
+      <fileset dir="conf" includes="*.tld"/>
+    </copy>    
+
+    <!-- Copy the resource properties files -->
+    <copy todir="${build.library}/classes">
+      <fileset dir="${library.src}">
+	<include name="**/*.properties"/>
+      </fileset>
+    </copy>
+    
+    <!-- Create the JSTL API jar -->
+    <jar jarfile="${build.library}/lib/jstl.jar"
+         basedir="${build.library}/classes"
+         includes="javax/**">
+      <manifest>
+        <attribute name="Specification-Title" value="JavaServer Pages Standard Tag Library (JSTL)"/>
+        <attribute name="Specification-Version" value="1.1"/>
+        <attribute name="Implementation-Title" value="JavaServer Pages Standard Tag Library API Reference Implementation"/>
+        <attribute name="Implementation-Version" value="${standard-version}"/>
+        <attribute name="Implementation-Vendor" value="Sun Microsystems, Inc."/>
+        <attribute name="Implementation-Vendor-Id" value="com.sun"/>
+        <attribute name="Extension-Name" value="javax.servlet.jsp.jstl"/>
+      </manifest>         
+    </jar>        
+    
+    <!-- Create the implementation jar -->
+    <jar jarfile="${build.library}/lib/standard.jar">
+      <fileset dir="${build.library}/classes">
+        <include name="org/**"/>
+      </fileset>
+      <fileset dir="${build.library}">
+        <include name="META-INF/*.tld"/>
+      </fileset>
+      <manifest>
+        <attribute name="Specification-Title" value="JavaServer Pages Standard Tag Library (JSTL)"/>
+        <attribute name="Specification-Version" value="1.1"/>
+        <attribute name="Implementation-Title" value="jakarta-taglibs 'standard': an implementation of JSTL"/>
+        <attribute name="Implementation-Version" value="${standard-version}"/>
+        <attribute name="Implementation-Vendor" value="Apache Software Foundation"/>
+        <attribute name="Implementation-Vendor-Id" value="org.apache"/>
+        <attribute name="Extension-Name" value="org.apache.taglibs.standard"/>
+      </manifest>         
+    </jar>        
+    
+    <!-- All jar files required at runtime are copied in the 'lib' dir -->
+     
+    <antcall target="processIfPropSet">
+      <param name="prop" value="jdbc2_0-stdext.jar"/>
+      <param name="task" value="copyIfPropSet"/>
+      <param name="file" value="${jdbc2_0-stdext.jar}"/>
+      <param name="todir" value="${build.library}/lib/old-dependencies"/>
+    </antcall>
+
+    <antcall target="processIfPropSet">
+      <param name="prop" value="jaxp-api.jar"/>
+      <param name="task" value="copyIfPropSet"/>
+      <param name="file" value="${jaxp-api.jar}"/>
+      <param name="todir" value="${build.library}/lib/old-dependencies"/>
+    </antcall>
+
+    <antcall target="processIfPropSet">
+      <param name="prop" value="dom.jar"/>
+      <param name="task" value="copyIfPropSet"/>
+      <param name="file" value="${dom.jar}"/>
+      <param name="todir" value="${build.library}/lib/old-dependencies"/>
+    </antcall>
+
+    <antcall target="processIfPropSet">
+      <param name="prop" value="sax.jar"/>
+      <param name="task" value="copyIfPropSet"/>
+      <param name="file" value="${sax.jar}"/>
+      <param name="todir" value="${build.library}/lib/old-dependencies"/>
+    </antcall>
+           
+    <antcall target="processIfPropSet">
+      <param name="prop" value="xalan.jar"/>
+      <param name="task" value="copyIfPropSet"/>
+      <param name="file" value="${xalan.jar}"/>
+      <param name="todir" value="${build.library}/lib/old-dependencies"/>
+    </antcall>
+
+    <antcall target="processIfPropSet">
+      <param name="prop" value="xercesImpl.jar"/>
+      <param name="task" value="copyIfPropSet"/>
+      <param name="file" value="${xercesImpl.jar}"/>
+      <param name="todir" value="${build.library}/lib/old-dependencies"/>
+    </antcall>
+
+  </target>
+
+  <!-- Compile the examples application -->
+  <target name="examples-build" depends="library-build">
+
+    <!-- Compile the examples source code -->
+    <javac srcdir="${examples.src}" destdir="${build.examples}/WEB-INF/classes"
+           classpath="${servlet24.jar}:${jsp20.jar}:${build.library}/classes"
+           debug="${compile.debug}"
+           deprecation="${compile.deprecation}"
+           optimize="${compile.optimize}"/>
+  
+    <!-- Copy web.xml + examples TLD -->
+    <copy todir="${build.examples}/WEB-INF">
+      <fileset dir="${examples.src}/conf"/>
+    </copy>
+    
+    <!-- Copy web pages -->
+    <copy todir="${build.examples}">
+      <fileset dir="${examples.src}/web"/>
+    </copy>
+        
+    <!-- copy the runtime jar files -->
+    <copy todir="${build.examples}/WEB-INF/lib">
+      <fileset dir="${build.library}/lib" includes="*.jar"/>
+    </copy>
+    
+  </target>
+
+  <!-- Compile the documentation application -->
+  <target name="documentation-build" depends="prepare-build">
+  
+    <copy todir="${build.doc}/WEB-INF">
+      <fileset dir="${doc.src}/conf"/>
+    </copy>
+    
+    <copy todir="${build.doc}">
+      <fileset dir="${doc.src}/web">
+        <include name="**/*.html"/>
+      </fileset>
+    </copy>    
+  </target>
+  
+  <!-- =================================================================== -->
+  <!-- Create the Distribution                                             -->
+  <!-- =================================================================== -->
+
+  <!-- Create the entire set of distribution files -->
+  <target name="dist" depends="library-dist,examples-dist,documentation-dist,javadoc-dist"/>
+
+  <!-- Create the library distribution files -->
+  <target name="library-dist" depends="library-build, prepare-dist">
+
+    <!-- Copy the runtime jar files -->
+    <copy todir="${dist.library}/lib">
+      <fileset dir="${build.library}/lib" includes="**/*.jar"/>
+    </copy>
+
+    <!-- All TLDs are copied in the 'tld' dir of the distribution -->
+    <copy todir="${dist.dir}/${taglib.name}/tld">
+      <fileset dir="${conf.src}" includes="*.tld"/>
+    </copy>
+      
+    <!-- LICENSE and NOTICE files copied at the top level of the distribution -->
+    <copy file="../LICENSE" tofile="${dist.library}/LICENSE"/>
+    <copy file="../NOTICE" tofile="${dist.library}/NOTICE"/>
+
+    <!-- README file copied at the top level of the distribution -->
+    <copy file="README_bin.txt" tofile="${dist.library}/README"/>
+    
+  </target>
+
+  <!-- Create the examples application WAR file -->
+  <target name="examples-dist" depends="examples-build, prepare-dist">    
+      <!-- create the jar for the examples webapp -->  
+      <jar jarfile="${dist.examples}" basedir="${build.examples}"/>
+  </target>
+
+  <!-- Create the documentation application WAR file -->
+  <target name="documentation-dist" depends="documentation-build, prepare-dist">
+      <jar jarfile="${dist.doc}" basedir="${build.doc}" excludes="intro.html"/>
+      <mkdir dir="${taglibs.doc}"/>
+      <copy todir="${taglibs.doc}">
+          <fileset dir="${build.doc}">
+              <exclude name="WEB-INF/**"/>
+          </fileset>
+      </copy>
+  </target>
+  
+  <!-- Create the javadocs -->
+  <target name="javadoc-dist" depends="prepare-dist">
+   <javadoc packagenames="javax.servlet.jsp.jstl.*"
+            sourcepath="src"
+            classpath="${servlet24.jar}:${jsp20.jar}:${jdbc2_0-stdext.jar}:${jaxp-api.jar}:${dom.jar}:${sax.jar}:${xercesImpl.jar}:${xalan.jar}"
+            destdir="${dist.library}/javadoc"
+            bottom='<font size="-1">Copyright 2003 Sun Microsystems, Inc. All Rights Reserved.</font>'/>
+  </target>
+
+  <!-- =================================================================== -->
+  <!-- Nightly (components generated for the website)                      -->
+  <!-- =================================================================== -->
+  
+  <target name="dist-nightly" depends="dist">
+    <!-- website intro page for the taglib -->
+    <style in="${xml.src}/intro.xml"
+           destdir="${build.doc}"                                          
+           out="${build.doc}/intro.html"
+           style="${taglibs.xsl}">
+      <param name="prefix" expression="../../"/>
+    </style>
+    <copy file="${build.doc}/intro.html" todir="${taglibs.doc}"/>
+  </target>    
+  
+  <!-- =================================================================== -->
+  <!-- Public utility targets                                              -->
+  <!-- =================================================================== -->
+ 
+  <!-- Delete build and dist directories so we can start from scratch -->
+  <target name="clean">
+    <delete dir="${build.dir}/${taglib.name}"/>
+    <delete dir="${dist.dir}/${taglib.name}"/>
+  </target>
+
+  <!-- =================================================================== -->
+  <!-- Private utility targets                                              -->
+  <!-- =================================================================== -->
+  
+  <!-- Check the availability of a required jar -->
+  <target name="requiredJar">
+    <echo message="  ${prop}"/>
+    <available file="${file}" property="requirement.satisfied"/>
+    <antcall target="requiredJarFailed"/>
+  </target>
+
+  <!-- Support for target 'requiredJar' -->
+  <target name="requiredJarFailed" unless="requirement.satisfied">
+    <echo message="The property ${prop} must be set to a jar file containing"/>
+    <echo message="the '${desc}'."/>
+    <fail message="Current value for ${prop} is: ${file}."/>
+  </target>
+  
+  <!-- Process a target only if a property is set.
+       Allows us to ignore some dependencies that are included in
+       J2SE 1.4 but were not prior to that. -->
+  <target name="processIfPropSet">
+    <echo message="  ${prop}"/>
+    <condition property="prop.specified">
+      <isSet property="${prop}"/>
+    </condition>
+    <antcall target="${task}"/>
+    <antcall target="${task}Not"/>
+  </target>
+
+  <!-- Check the availability of a required jar only if property is set -->
+  <target name="requiredJarIfPropSet" if="prop.specified">
+    <antcall target="requiredJar"/>
+  </target>
+
+  <!-- Warning message when required jar is ignored because the property
+       is not set. -->
+  <target name="requiredJarIfPropSetNot" unless="prop.specified">
+    <echo message="  Ignoring dependency on ${prop} because property is not set."/>
+    <echo message="  OK as long as both compile and run-time environments are at least J2SE 1.4."/>
+  </target>
+
+  <!-- Copy file only if property is set -->
+  <target name="copyIfPropSet" if="prop.specified">
+    <copy file="${file}" todir="${todir}"/>
+  </target>
+
+  <!-- Warning message when file is not copied because the property
+       is not set. -->
+  <target name="copyIfPropSetNot" unless="prop.specified">
+    <echo message="  Ignoring copy of ${prop} because property is not set."/>
+  </target>  
+
+  <!-- =================================================================== -->
+  <!-- Perform an official release -->
+  <!-- =================================================================== -->
+  <target name="release" depends="dist">
+    <mkdir dir="${release.dir}"/>
+    <antcall target="${release.pre}"/>
+    <!-- Copy the taglib to the release dir -->
+    <copy todir="${release.dir}" >
+      <fileset dir="${dist.dir}/${taglib.name}" excludes="doc/**"/>
+    </copy>
+    <copy file="../LICENSE"   tofile="${release.dir}/LICENSE"/>
+    <copy file="../NOTICE"    tofile="${release.dir}/NOTICE"/>
+    <copy file="../README"    tofile="${release.dir}/README"/>
+    <zip zipfile="${dist.dir}/${release.name}.zip"
+       basedir="${dist.dir}" includes="${release.name}/**"/>
+    <tar tarfile="${dist.dir}/${release.name}.tar"
+       basedir="${dist.dir}" includes="${release.name}/**"/>
+    <gzip zipfile="${dist.dir}/${release.name}.tar.gz"
+          src="${dist.dir}/${release.name}.tar"/>
+    <delete dir="${dist.dir}/${release.name}"/> 
+    <delete file="${dist.dir}/${release.name}.tar"/> 
+    <antcall target="${release.post}"/>
+  </target>
+
+  <!-- target that does nothing -->
+  <target name="nop"/>
+
+  <!-- =================================================================== -->
+  <!-- Unit Test PassThru Targets -->
+  <!-- =================================================================== -->
+  <target name="test" depends="build">
+    <ant antfile="build-tests.xml" target="run.test"/>
+  </target>
+
+  <target name="run.cactus" depends="build">
+    <ant antfile="build-tests.xml" target="run.cactus"/>
+  </target>
+
+  <target name="run.junit" depends="build">
+    <ant antfile="build-tests.xml" target="junit"/>
+  </target>
+
+</project>
diff --git a/standard/README_bin.txt b/standard/README_bin.txt
new file mode 100644
index 0000000..2ec7a04
--- /dev/null
+++ b/standard/README_bin.txt
@@ -0,0 +1,138 @@
+---------------------------------------------------------------------------
+Standard Tag Library 1.1 -- BINARY DISTRIBUTION
+---------------------------------------------------------------------------
+Thanks for downloading this release of the Standard tag library, 
+an implementation of the JavaServer Pages(tm)(JSP) 
+Standard Tag Library (JSTL).
+
+JSTL is an effort of the Java Community Process (JCP) and
+comes out of the JSR-052 expert group. For more information on JSTL,
+please go to http://java.sun.com/products/jstl.
+
+We hope you find the tags, documents, and examples in this binary
+distribution of interest.
+
+---------------------------------------------------------------------------
+LIBRARY DEPENDENCIES
+
+This version of the Standard Tag Library has the following runtime
+dependencies:
+
+   1. Dependencies provided by the JSP 2.0 container:
+      - Servlet 2.4
+      - JSP 2.0
+
+   2. Dependencies provided in newer J2SEs (1.4.2 and higher)
+      - JAXP 1.2 
+      - Xalan 2.5 
+      - JDBC Standard Extension 2.0
+
+Since all of the dependencies in (2) are included in Sun's
+distribution of J2SE 1.4.2 (and higher), this is therefore the J2SE
+version of choice to use the standard tag library.
+
+If the java platform under which you run your JSP container does not
+provide these dependencies, they must be made available either globally
+to all web-applications by your container, or individually within the
+WEB-INF/lib directory of your web-application.
+
+For convenience, these jar files have been included in directory 
+lib/old-dependencies of this distribution (assuming the build process
+of this distribution included them). If you would like to download
+these jar files yourself, instructions on where you can get them are 
+included below.
+
+---
+JAXP 1.2
+
+The JAXP 1.2 jar files can be obtained in the Java Web Services
+Developer Pack (JWSDP) available at 
+http://java.sun.com/products/jwsdp.
+
+  - jaxp-api.jar
+  - dom.jar
+  - sax.jar
+  - xercesImpl.jar
+
+---
+Xalan 2.5
+
+The Xalan jar file can be obtained in the Java Web Services
+Developer Pack (JWSDP) available at 
+http://java.sun.com/products/jwsdp, as well as from 
+Apache at http://xml.apache.org/xalan-j.
+
+  - xalan.jar
+
+Please note that if you use Sun's distribution of J2SE 1.4.1, you must
+supersede the version of xalan.jar provided by the J2SE with version
+2.5 or higher of Xalan.  This newer version of xalan.jar must then be
+made available through the endorsed dirs mechanism.
+
+---
+JDBC Standard Extension 2.0
+
+The JDBC 2.0 Optional Package can be obtained from:
+http://java.sun.com/products/jdbc/download.html
+
+  - jdbc2_0-stdext.jar
+
+---------------------------------------------------------------------------
+WAR Files
+
+The following two files are standalone web applications (WARs) that are
+designed to work out of the box in order to help you learn JSTL:
+
+   standard-doc.war                Documentation
+   standard-examples.war           Simple examples of JSTL tags
+
+Note that 'standard-examples.war' will work out-of-the-box as long 
+as the java platform under which you run your JSP container provides
+all the dependencies mentioned above (see Library Dependencies). 
+This is the case if using Sun's distribution of J2SE 1.4.2 (and higher).
+
+If not all dependencies are provided by your runtime, then they must 
+be made available to the web application as explained in section
+"Library Dependencies".
+
+---------------------------------------------------------------------------
+USING THE STANDARD TAG LIBRARY
+
+To use this distribution with your own web applications, simply copy the JAR
+files in the 'lib' directory (jstl.jar and standard.jar) to your application's 
+WEB-INF/lib directory (add the other dependencies as well if your runtime
+does not already provide them). Then, import JSTL into your pages with the 
+following directives:
+
+  CORE LIBRARY
+    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+
+  XML LIBRARY
+    <%@ taglib prefix="x" uri="http://java.sun.com/jsp/jstl/xml" %>
+
+  FMT LIBRARY 
+    <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
+
+  SQL LIBRARY
+    <%@ taglib prefix="sql" uri="http://java.sun.com/jsp/jstl/sql" %>
+
+  FUNCTIONS LIBRARY
+    <%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
+
+---------------------------------------------------------------------------
+COMPATIBILITY
+
+The 1.1 version of the Standard Taglib has been tested under Tomcat 5.0.3
+and should work in any compliant JSP 2.0 container.
+
+---------------------------------------------------------------------------
+COMMENTS AND QUESTIONS
+
+Please join the taglibs-user at jakarta.apache.org mailing list if you have
+general usage questions about JSTL.
+
+Comments about the JSTL specification itself should be sent to
+jsr-52-comments at jcp.org.
+
+Enjoy!
+
diff --git a/standard/README_src.txt b/standard/README_src.txt
new file mode 100644
index 0000000..405d8a1
--- /dev/null
+++ b/standard/README_src.txt
@@ -0,0 +1,344 @@
+---------------------------------------------------------------------------
+Standard Tag Library 1.1 -- SOURCE DISTRIBUTION
+---------------------------------------------------------------------------
+Thanks for downloading the source code of the Standard tag library, 
+an implementation of the JavaServer Pages(tm)(JSP) 
+Standard Tag Library (JSTL).
+
+JSTL is an effort of the Java Community Process (JCP) and
+comes out of the JSR-052 expert group. For more information on JSTL,
+please go to http://java.sun.com/products/jstl.
+
+---------------------------------------------------------------------------
+BUILD ENVIRONMENT SETUP
+
+---
+J2SE (Java 2 Standard Edition)
+
+Download and install Sun's distribution of J2SE 1.4.2 (or higher) 
+for your operating system platform. J2SE can be found at 
+http://java.sun.com/j2se.
+
+Sun's distribution of J2SE 1.4.2 includes many of the libraries that
+standard 1.1 depends on. However, please note that standard 1.1 will
+compile and run on previous versions of J2SE (from 1.3 up to 1.4.1) as
+long as the standard 1.1 dependencies not included in these versions
+of the J2SE are properly setup.  See section 'LIBRARY DEPENDENCIES'
+for details.
+
+  - Set a JAVA_HOME environment variable to point at the directory 
+    where J2SE is installed.
+  - Add the JAVA_HOME/bin directory to your PATH.
+
+---
+Ant
+
+Download and install version 1.5 or higher of the Jakarta Ant Project
+distribution. Ant can be fount at http://ant.apache.org.
+
+  - Set the ANT_HOME environment variable to point at your Ant 
+    distribution directory 
+  - Add the ANT_HOME/bin directory to your PATH.
+
+---------------------------------------------------------------------------
+LIBRARY DEPENDENCIES
+
+This version of the Standard Tag Library has the following compile-time
+dependencies:
+
+   1. Dependencies not included in J2SE:
+      - Servlet 2.4
+      - JSP 2.0
+
+   2. Dependencies included in newer J2SEs (1.4.2 and higher)
+      - JAXP 1.2 
+      - Xalan 2.5 
+      - JDBC Standard Extension 2.0
+
+Since all of the dependencies in (2) are included in Sun's
+distribution of J2SE 1.4.2 (or higher), this is therefore the J2SE
+version of choice to compile and run the standard tag library.
+
+If you still need the jar files for the dependencies listed in (2), 
+instructions on where you can get these jar files are included below.
+
+---
+build.properties
+
+- Copy the file standard/build_sample_standard.properties to build.properties.
+
+- Edit build.properties and make the following modifications:
+    - Set the "base.dir" property in build.properties to the base directory
+      of your 'standard' distribution. It must be an absolute path.
+    - Set the jar file properties to the absolute path and filename 
+      for the jar files required to build the standard tag library
+      (see below).
+
+---
+Servlet 2.4 and JSP 2.0
+
+Download and install the Servlet 2.4 and JSP 2.0 APIs.  The jar files
+for these APIs may be found in distributions of jakarta-servlet-api-5-bin
+and jakarta-jsp-api-5-bin at http://cvs.apache.org/builds/jakarta-tomcat-5/nightly.  
+They are also included in Tomcat 5, available at http://jakarta.apache.org/tomcat.
+
+Set the following properties in build.properties to the
+file paths of the jars:
+  - servlet24.jar
+  - jsp20.jar
+
+---
+JAXP 1.2
+[required only if building with versions of J2SE that do not include
+the JAXP APIs, such as J2SE 1.3]
+
+The JAXP 1.2 jar files can be obtained in the Java Web Services
+Developer Pack (JWSDP) available at 
+http://java.sun.com/products/jwsdp.
+
+Set the following properties in build.properties to the
+file paths of the jars:
+  - jaxp-api.jar
+  - dom.jar
+  - sax.jar
+  - xercesImpl.jar
+
+---
+Xalan 2.5
+[required only if building with J2SE 1.3 up to J2SE 1.4.1]
+
+The Xalan jar file can be obtained in the Java Web Services
+Developer Pack (JWSDP) available at 
+http://java.sun.com/products/jwsdp, as well as from 
+Apache at http://xml.apache.org/xalan-j.
+
+Set the "xalan.jar" property in build.properties to the
+jar file of Xalan.
+
+If using jdk 1.3, put xalan.jar in the lib directory
+of ant so XSLT transformations of documentation can be 
+properly done.
+
+---
+JDBC Standard Extension 2.0
+[required only if building with J2SE 1.3]
+
+The JDBC 2.0 Optional Package can be obtained from:
+http://java.sun.com/products/jdbc/download.html
+
+Set the "jdbc2_0-stdext.jar" property in build.properties to the
+JDBC 2.0 Standard Extensions jar file path.
+
+---------------------------------------------------------------------------
+Building the Standard tag library
+
+To build the distribution set your current directory to the 'standard' 
+directory into which you unpacked the distribution.
+
+Build 'standard' by executing ant in a shell. Some common build targets
+include:
+
+       > ant         <-- builds the intermediate form of the library,
+                         documentation, and example targets
+       > ant dist    <-- builds all the distribution targets
+       > ant clean   <-- deletes intermediate results so that target can
+                         be rebuilt from scratch.
+
+Two directory hierarchies are created to contain the results of the
+build:
+
+{base.dir}/
+    build/           <-- Contains intermediate form results of
+                         building standard custom library
+    dist/            <-- Contains the files that will be included
+                         in the binary distribution of the
+                         standard project
+
+The following directory and files are created when doing a build:
+
+   * build/standard - Location of all directories and files built for the 
+     standard taglib.
+   * build/standard/standard - Results of the build process
+     (classes, jar files, tlds)
+   * build/standard/standard-doc/ - Files used to create the
+     standard-doc.war file
+   * build/standard/standard-examples/ - Files used to create the 
+     standard-examples.war file.
+
+The following directory and files are created when doing a distribution
+build:
+
+   * dist/standard/ - Location of all files built for a binary
+     distribution of the taglib.
+   * dist/standard/README - Information to use the binary distribution
+     of the standard tablib.
+   * dist/standard/javadoc/ - The javadocs
+   * dist/standard/lib/ - The standard jar files: jstl.jar and
+     standard.jar
+   * dist/standard/tld/ - Directory with the Tag Lib Descriptors for 
+     the tag library.
+   * dist/standard/standard-doc.war - Tag Library documentation
+     war file.
+   * dist/standard/standard-examples.war - Tag Library examples
+     war file.
+   * dist/standard/tld - Directory with the Tag Lib Descriptors for 
+     the tag library.
+
+---------------------------------------------------------------------------
+USING THE STANDARD TAG LIBRARY
+
+See the README file of the binary distribution you have built with these
+instructions.
+
+---------------------------------------------------------------------------
+
+UNIT TESTING THE STANDARD TAG LIBRARY
+
+---------------------------------------------------------------------------
+OVERVIEW OF THE UNIT TEST FRAMEWORK
+
+The Unit test directory hierarchy should mimic the RI implementation hierarchy. This way, you have a mapping between the unit test and the file that it covers.
+
+If there's no appropriate mapping you can put the test in the general test directory:
+
+<JSTL_HOME>/test/org/apache/taglibs/standard 
+
+The Test should be written using Junit Test name conventions and start with
+"Test*.java"
+
+Here is the Unit test directory hierarchy:
+
+  <JSTL_HOME>/
+    test/
+      conf/                            <-- unit test configuration files
+      web/                             <-- unit test web application files
+        WEB-INF/
+      org/
+        apache/
+          taglibs/
+            standard/
+              extra/
+                spath/
+              functions/
+              lang/
+                jstl/
+              resources/
+              tag/
+                common/
+                  core/
+                  fmt/
+                  sql/
+                  xml/
+                el/
+                  core/
+                  fmt/
+                  sql/
+                  xml/
+                rt/
+                  core/
+                  fmt/
+                  sql/
+                  xml/
+              tei/
+              tlv/
+
+
+---------------------------------------------------------------------------
+UNIT TEST BUILD ENVIRONMENT SETUP
+
+In order to build the Standard Unit Test Framework, you will need to set the
+following properties and download the corresponding implementation files. See the "build_sample_standard.properties" for the definitions:
+
+        build.dir                     Base directory into which we are building
+                                      the components.
+        build.classes                 Base JSTL classes directory 
+
+        jstl.jar                      JSTL API jar file
+        standard.jar                  JSTL implementation jar file
+
+        servlet24.jar                 Servlet jar
+        jsp20.jar                     JSP jar
+
+        junit.jar                     JUnit jar
+
+        cactus.jar                    Cactus jar 
+        cactus.ant.jar                Cactus custom Ant tasks jar
+        aspectjrt.jar                 Cactus AspectJ Language Support jar
+        httpclient.jar                Cactus httpclient jar
+        commons-logging.jar           Cactus logging jar
+
+        tomcat.home                   Home directory where Tomcat 
+                                      is installed
+        tomcat.webapps                Tomcat webapps directory
+        username                      Tomcat username with manager role
+                                      privileges
+        password                      password for the user with manager
+                                      privileges
+
+        web.server.host               hostname for the running webserver
+        web.server.port               port for the running webserver
+
+        compile.debug                 debug mode for compilation
+        compile.deprecation           deprecation mode for compilation
+        compile.optimize              optimization mode for compilation
+
+---------------------------------------------------------------------------
+BUILDING THE UNIT TESTS
+
+Some common unit test build targets include:
+    > ant test                       <-- Build, deploy and run all the tests
+    > ant run.cactus                 <-- Build, deploy and run the Cactus tests
+    > ant run.junit                  <-- Build, deploy and run the Junit tests
+
+The following directories and files are created when building the unit tests:
+
+To execute the build-tests.xml unit test targets directly you can do the following:
+
+    > ant -f build-tests.xml <target>
+
+Some examples of targets available in the build-tests.xml file include:
+
+    > ant -f build-tests.xml props    <-- Print out test environment properties
+    > ant -f build-tests.xml undeploy <-- Manually undeploy the Cactus 
+                                          Tests web application
+    > ant -f build-tests.xml deploy   <-- Manually deploy the Cactus Test 
+                                          web application
+
+The following directories will be created when building the Unit Tests:
+    build/
+      standard/
+        standard/
+          test/
+            WEB-INF/
+              classes/
+                ...
+              lib/
+            org/
+                ...                  
+
+A Unit Test web application war file will also be created. It is located here:
+    build/standard/standard/jstl_test.war
+
+---------------------------------------------------------------------------
+UNIT TEST RUNTIME SETUP
+
+You will need to have the Tomcat manager administration application enabled in
+order to run the tests. The Unit Test build file uses the Tomcat manager to
+automatically deploy and undeploy the Cactus tests.
+
+The following runtime properties need to be properly set in order to successfully run the unit tests:
+
+        tomcat.webapps                Tomcat webapps directory
+        username                      Tomcat username with manager role
+                                      privileges
+        password                      password for the user with manager
+                                      privileges
+
+        web.server.host               hostname for the running webserver
+        web.server.port               port for the running webserver
+
+The Tomcat manager application may sometimes get into an unstable state after
+many web application deployments and undeployments. If the Cactus tests start
+failing for unknown reasons, stop your web container and clean out your work
+directory before restarting.
+---------------------------------------------------------------------------
diff --git a/standard/build-tests.xml b/standard/build-tests.xml
new file mode 100644
index 0000000..2f31583
--- /dev/null
+++ b/standard/build-tests.xml
@@ -0,0 +1,393 @@
+<project name="JSTL Unit Tests" default="run.test" basedir=".">
+
+<!--
+        This is a generic build.xml file for Ant that is used to run the
+        JSTL unit tests.
+-->
+
+<!-- ========== Prerequisite Properties =================================== -->
+
+
+<!--
+        These properties MUST be set on the "ant" command line, the "antrc"
+        properties file in your home directory, or from settings in a superior
+        build.xml script.
+
+        build.dir                     Base directory into which we are building
+                                      the components.
+        build.classes                 Base JSTL classes directory 
+
+        jstl.jar                      JSTL API jar file
+        standard.jar                  JSTL implementation jar file
+
+        servlet24.jar                 Servlet 2.4 jar
+        jsp20.jar                     JSP 2.0 jar
+
+        junit.jar                     JUnit jar
+
+        cactus.jar                    Cactus jar 
+        cactus.ant.jar                Cactus custom Ant tasks jar
+        aspectjrt.jar                 Cactus AspectJ Language Support jar
+        httpclient.jar                Cactus httpclient jar
+        commons-logging.jar           Cactus logging jar
+
+        tomcat.home                   Home directory where Tomcat 
+                                      is installed
+        tomcat.webapps                Tomcat webapps directory
+        username                      Tomcat username with manager role
+                                      privileges
+        password                      password for the user with manager
+                                      privileges
+
+        web.server.host               hostname for the running webserver
+        web.server.port               port for the running webserver
+
+        compile.debug                 debug mode for compilation
+        compile.deprecation           deprecation mode for compilation
+        compile.optimize              optimization mode for compilation
+
+-->
+
+<!-- ========== Initialization Properties ================================= -->
+
+<!-- ========== Derived Properties ======================================== -->
+
+<!--
+        These property values are derived from values defined above, and
+        generally should NOT be overridden by command line settings
+-->
+
+  <property file="build.properties"/>              <!-- Component local   -->
+  <property file="../build.properties"/>           <!-- Commons local     -->
+  <property file="${user.home}/build.properties"/> <!-- User local        -->
+
+  <!-- Default value for debugging arguments is no.  Override in
+       build.properties -->
+  <property name="debug.jvm.args" value=""/>
+
+  <!-- Source directory for tests -->
+  <property name="src.test.dir" 
+            value="${basedir}/test"/>
+
+  <!-- Configuration directory for tests -->
+  <property name="conf.test.dir" 
+            value="test/conf"/>
+
+  <!-- Output directory for tests -->
+  <property name="out.test.dir" 
+            value="${basedir}/build/standard/standard/test"/>
+
+  <property name="test.context.path" 
+            value="jstl_test"/>
+  <property name="test.war" 
+            value="${test.context.path}.war"/>
+
+  <!-- all of these properties must have valid values -->
+  <property name="catalina-ant.jar" 
+            value="${tomcat.home}/server/lib/catalina-ant.jar"/>
+  <property name="cactus.home" 
+            value="${tomcat.home}/../jakarta-cactus-13-1.4.1"/>
+  <property name="cactus.ant.jar" 
+            value="${cactus.home}/lib/cactus-ant-1.4.1.jar"/>
+  <property name="cactus.jar" 
+            value="${cactus.home}/lib/cactus-1.4.1.jar"/>
+  <property name="aspectjrt.jar" 
+            value="${cactus.home}/lib/aspectjrt-1.0.5.jar"/>
+  <property name="httpclient.jar" 
+            value="${cactus.home}/lib/commons-httpclient-2.0alpha1-20020606.jar"/>
+
+  <property name="junit.jar" 
+            value="${tomcat.home}/../junit3.8.1/junit.jar"/>
+
+  <property name="standard.jar" 
+            value="${tomcat.home}/jstl/lib/standard.jar"/>
+    
+  <property name="username" value="tomcat"/>
+  <property name="password" value="tomcat"/>
+
+  <property name="tomcat.manager.url" 
+            value="http://${web.server.host}:${web.server.port}/manager"/>
+
+  <property name="cactus.contextURL"
+            value="http://${web.server.host}:${web.server.port}/${test.context.path}"/>
+
+  <target name="props"
+          description="Display resolved properties" >
+
+    <!-- Info on build environment -->
+    <echo>---------- Environment Information ----------</echo>
+    <echo>java.home: ${java.home}</echo>
+    <echo>ant.java.version: ${ant.java.version}</echo>
+    <echo>jstl.jar=${jstl.jar}</echo>
+    <echo>standard.jar=${standard.jar}</echo>
+    <echo>deprecation: ${compile.deprecation}</echo>
+    <echo>debug: ${compile.debug}</echo>
+    <echo>optimize: ${compile.optimize}</echo>
+    <echo>---------- Dependencies ---------------------</echo>
+    <echo>tomcat.home=${tomcat.home}</echo>
+    <echo>servlet24.jar: ${servlet24.jar}</echo>
+    <echo>jsp20.jar: ${jsp20.jar}</echo>
+    <echo>junit.jar: ${junit.jar}</echo>
+    <echo>cactus.home: ${cactus.home}</echo>
+    <echo>cactus.ant.jar: ${cactus.ant.jar}</echo>
+    <echo>cactus.jar: ${cactus.jar}</echo>
+    <echo>aspectjrt.jar: ${aspectjrt.jar}</echo>
+    <echo>httpclient.jar: ${httpclient.jar}</echo>
+    <echo>commons-logging.jar: ${commons-logging.jar}</echo>
+    <echo>---------- Build directories ----------------</echo>
+    <echo>build.dir: ${build.dir}</echo>
+    <echo>build.classes: ${build.classes}</echo>
+    <echo>dist.dir: ${dist.dir}</echo>
+    <echo>---------- Run-Time ----------------</echo>
+    <echo>tomcat.webapps: ${tomcat.webapps}</echo>
+    <echo>username: ${username}</echo>
+    <echo>password: ${password}</echo>
+    <echo>web.server.host: ${web.server.host}</echo>
+    <echo>web.server.port: ${web.server.port}</echo>
+  </target>
+
+  <!-- Compilation Classpath -->
+  <path id="compile.classpath">
+    <pathelement location="${jstl.jar}"/>
+    <pathelement location="${standard.jar}"/>
+    <pathelement location="${servlet24.jar}"/>
+    <pathelement location="${jsp20.jar}"/>
+    <pathelement location="${junit.jar}"/>
+    <pathelement location="${cactus.jar}"/>
+    <pathelement location="${httpclient.jar}"/>
+    <pathelement location="${aspectjrt.jar}"/>
+    <pathelement location="${build.classes}"/>
+    <pathelement location="${tomcat.home}/bin/bootstrap.jar"/>
+    <!-- For cactus.properties -->
+    <!--
+      <pathelement location="${conf.test.dir}"/>
+    -->
+  </path>
+
+  <path id="catalina-ant.classpath">
+    <pathelement location="${catalina-ant.jar}"/>
+  </path>
+
+<!-- ========== Custom Tasks Definition ================================== -->
+
+  <taskdef name="install" classname="org.apache.catalina.ant.InstallTask">
+    <classpath>
+      <pathelement location="${catalina-ant.jar}" />
+    </classpath>
+  </taskdef>
+
+  <taskdef name="remove" classname="org.apache.catalina.ant.RemoveTask">
+    <classpath>
+      <pathelement location="${catalina-ant.jar}" />
+    </classpath>
+  </taskdef>
+
+<!-- ========== Executable Targets ======================================== -->
+
+  <target name="init">
+    <uptodate property="skip.build" 
+              targetfile="${out.test.dir}/last-testrun">
+      <srcfiles dir="${basedir}">
+        <include name="src/**/*.*"/>
+        <include name="test/**/*.*"/>
+      </srcfiles>
+    </uptodate>
+  </target>
+
+<!-- ========== Test Preparation ========================================= -->
+
+  <!-- Create directories and copy files for the tests -->
+  <target name="prepare.test" 
+          depends="init">
+
+    <!-- Create target directories for classes -->
+    <mkdir dir="${out.test.dir}/WEB-INF/classes"/>
+
+    <!-- Create a lib directory where needed libs for the test war will
+         be put -->
+    <mkdir dir="${out.test.dir}/WEB-INF/lib"/>
+
+  </target>
+
+<!-- ========== Build and Package Tests =================================== -->
+
+  <!-- Compile unit tests -->
+  <target name="compile.test" depends="prepare.test">
+
+    <javac srcdir="${src.test.dir}"
+           destdir="${out.test.dir}/WEB-INF/classes"
+           debug="${compile.debug}"
+           optimize="${compile.optimize}"
+           deprecation="${compile.deprecation}">
+      <classpath refid="compile.classpath"/>
+    </javac>
+    <copy todir="${out.test.dir}/WEB-INF/classes">
+      <fileset dir="${src.test.dir}" includes="**/*.properties"
+               excludes="conf/"/>
+    </copy>
+  </target>
+
+  <target name="copy-test-data-files">
+    <!-- Copy Unit test static files. -->
+    <copy todir="${out.test.dir}">
+      <fileset dir="${basedir}/test/web"/>
+      <fileset dir="${cactus.home}/web" includes="jspRedirector.jsp"/>
+    </copy>
+  </target>
+
+  <target name="war" 
+          description="put the test webapp in the WAR file format in out.test.dir"
+          depends="compile.test">
+
+    <!-- Copy needed libs in /lib -->
+    <copy file="${jstl.jar}" todir="${out.test.dir}/WEB-INF/lib"/>
+    <copy file="${standard.jar}" todir="${out.test.dir}/WEB-INF/lib"/>
+    <copy file="${junit.jar}" todir="${out.test.dir}/WEB-INF/lib"/>
+    <copy file="${cactus.jar}" todir="${out.test.dir}/WEB-INF/lib"/>
+    <copy file="${httpclient.jar}" todir="${out.test.dir}/WEB-INF/lib"/>
+    <copy file="${aspectjrt.jar}" todir="${out.test.dir}/WEB-INF/lib"/>
+
+    <!-- copy the all important web.xml -->
+    <echo message="out.test.dir ${out.test.dir}" />
+    <filter token="test.root.dir" value="${out.test.dir}"/>
+    <copy file="${src.test.dir}/web/WEB-INF/web.xml" todir="${out.test.dir}/WEB-INF"
+          filtering="on"/>
+    <copy todir="${out.test.dir}/WEB-INF/classes" overwrite="true">
+      <filterset>
+        <filter token="cactus.contextURL" value="${cactus.contextURL}"/>
+      </filterset>
+      <fileset dir="${src.test.dir}/conf">
+        <include name="cactus.properties"/>
+      </fileset>
+    </copy>
+    <!-- copy the test data files -->
+    <antcall target="copy-test-data-files"/>
+    <jar jarfile="${out.test.dir}/../${test.war}" basedir="${out.test.dir}"/>
+  </target>
+
+<!-- ========== Server Management Tasks =================================== -->
+
+  <target name="deploy" depends="war"
+          description="Install cactus unit test webapp">
+    <!-- unreliable in tomcat 5.0.24 -->
+    <install url="${tomcat.manager.url}" 
+             username="${username}" 
+             password="${password}"
+             path="/${test.context.path}"
+             war="file://${out.test.dir}/../${test.war}"/>
+  </target>
+
+  <target name="autodeploy" depends="war">
+    <copy todir="${tomcat.webapps}" overwrite="true">
+      <fileset dir="${out.test.dir}/..">
+        <include name="*.war"/>
+      </fileset>
+    </copy>
+  </target>
+
+  <target name="undeploy"
+          description="Remove cactus unit test webapp"> 
+    <remove url="${tomcat.manager.url}" 
+            username="${username}" 
+            password="${password}"
+            path="/${test.context.path}"/>
+    </target>
+
+  <target name="safe.undeploy"
+          description="Remove cactus unit test webapp, don't FAIL on error">
+    <exec executable="ant.bat" os="Windows 2000" failonerror="false">
+      <arg line="-f build-tests.xml -Dusername=${username} -Dpassword=${password} undeploy"/>
+    </exec>
+    <exec executable="ant" os="SunOS,Linux,Mac OS X" failonerror="false">
+      <arg line="-f build-tests.xml -Dusername=${username} -Dpassword=${password} undeploy"/>
+    </exec>
+  </target>
+
+<!-- ========== Cactus Test Task Definitions ============================== -->
+
+  <target name="cactus" depends="war">
+    <antcall target="safe.undeploy"/>
+    <antcall target="deploy"/>
+    <touch file="${out.test.dir}/last-testrun"/>
+    <!-- pause to allow container to finish deployment before running tests -->
+    <waitfor maxwait="20" maxwaitunit="second">
+      <http url="${cactus.contextURL}/JspRedirector"/>
+    </waitfor>
+    <antcall target="run.cactus"/>
+  </target>
+
+  <target name="cactus.force">
+    <antcall target="remove.tstamp"/>
+    <antcall target="cactus"/>
+  </target>
+
+  <target name="remove.tstamp">
+    <delete file="${out.test.dir}/last-testrun"/>
+  </target>
+
+  <!-- Run the Cactus tests using JUnit test runner -->
+  <target name="run.cactus">
+
+    <junit printsummary="yes" haltonfailure="yes" haltonerror="yes" fork="yes">
+      <classpath>
+        <pathelement path="${java.class.path}"/>
+        <pathelement location="${out.test.dir}/WEB-INF/classes"/>
+        <!-- For cactus.properties -->
+        <!--
+          <pathelement location="${conf.test.dir}"/>
+        -->
+      </classpath>
+      <classpath refid="compile.classpath"/>
+      <formatter type="plain" usefile="false"/>
+
+      <!-- Suite of Cactus tests to be executed -->
+      <batchtest>
+        <fileset dir="${src.test.dir}">
+          <include name="**/tag/**/Test*.java"/>
+          <exclude name="**/testutil/*.java"/>
+        </fileset>
+      </batchtest>
+    </junit>
+
+  </target>
+
+<!-- ========== Junit Test Task Definitions =============================== -->
+
+  <target name="junit" depends="compile.test,copy-test-data-files">
+    <junit printsummary="yes" haltonfailure="yes" haltonerror="yes" fork="yes">
+      <!-- uncomment the below line to enable attaching a debugger -->
+      <jvmarg line="${debug.jvm.args}"/>
+
+      <classpath>
+        <pathelement path="${java.class.path}"/>
+        <pathelement location="${out.test.dir}/WEB-INF/classes"/>
+      </classpath>
+      <classpath refid="compile.classpath"/>
+      <formatter type="plain" usefile="false"/>
+
+      <!-- Suite of Junit tests to be executed -->
+      <batchtest>
+        <fileset dir="${src.test.dir}">
+          <include name="**/TestVersion.java"/>
+          <exclude name="**/testutil/*.java"/>
+        </fileset>
+      </batchtest>
+    </junit>
+  </target>
+
+<!-- ========== Default Task Definitions =============================== -->
+
+  <target name="run.test" depends="junit,cactus"
+          description="Run all Junit and Cactus tests" >
+  </target>
+
+  <target name="clean">
+    <delete failonerror="no" includeEmptyDirs="yes">
+      <fileset dir="${out.test.dir}/..">
+        <include name="${test.war}"/>
+        <include name="test/"/>
+      </fileset>
+    </delete>
+  </target>
+
+</project>
diff --git a/standard/build.xml b/standard/build.xml
new file mode 100644
index 0000000..e0d0cf8
--- /dev/null
+++ b/standard/build.xml
@@ -0,0 +1,488 @@
+<project name="standard" default="build" basedir=".">
+
+  <!-- =================================================================== -->
+  <!-- Version Number                                                      -->
+  <!-- =================================================================== -->
+
+  <property name="standard-version" value="1.1.2" />
+  <property name="release.name" value="jakarta-taglibs-standard-${standard-version}" />
+  <property name="release.pre" value="nop" />
+  <property name="release.post" value="nop" />
+
+  <!-- =================================================================== -->
+  <!-- Inherited properties                                                -->
+  <!-- =================================================================== -->
+
+  <property file="build.properties"/>			<!-- Component local -->
+  <property file="../build.properties"/>		<!-- Commons local   -->
+  <property file="${user.home}/build.properties"/>	<!-- User local      -->
+  <property file="../common.properties"/>
+
+  <!-- =================================================================== -->
+  <!-- taglib specific properties                                                -->
+  <!-- =================================================================== -->
+    
+  <property name="taglib.name"    value="standard"/>
+
+  <!--
+        These property values are derived from the previously defined values,
+	and should not normally be overridden from the command line.
+
+        build.library               Target directory for tag library
+        build.examples		    Target directory for examples app
+        build.doc                   Target directory for documentation app
+	dist.library                Destination JAR for tag library
+	dist.examples		    Destination WAR for examples app
+	dist.doc                    Destination WAR for documentation app
+	dist.tld                    Destination TLD file for tag library
+  -->
+
+  <!-- =================================================================== -->
+  <!-- Destination Preparation                                             -->
+  <!-- =================================================================== -->
+
+  <target name="prepare-dependencies">
+
+    <!-- info on build environment -->
+
+    <echo>---------- Environment Information ----------</echo>
+    <echo>java.home: ${java.home}</echo>
+    <echo>ant.java.version: ${ant.java.version}</echo>
+    <echo>debug: ${compile.debug}</echo>
+    <echo>deprecation: ${compile.deprecation}</echo>
+    <echo>optimize: ${optimize.debug}</echo>
+    <echo>---------- Dependencies ---------------------</echo>
+    <echo>servlet24.jar: ${servlet24.jar}</echo>
+    <echo>jsp20.jar: ${jsp20.jar}</echo>
+    <echo>jdbc2_0-stdext.jar: ${jdbc2_0-stdext.jar}</echo>
+    <echo>jaxp-api.jar: ${jaxp-api.jar}</echo>
+    <echo>dom.jar: ${dom.jar}</echo>
+    <echo>sax.jar: ${sax.jar}</echo>
+    <echo>xalan.jar: ${xalan.jar}</echo>
+    <echo>xercesImpl.jar: ${xercesImpl.jar}</echo>
+    <echo>---------- Build directories ----------------</echo>
+    <echo>build.dir: ${build.dir}</echo>
+    <echo>build.library: ${build.library}</echo>
+    <echo>build.examples: ${build.examples}</echo>
+    <echo>build.doc: ${build.doc}</echo>
+    <echo>---------- Distribution directories ---------</echo>
+    <echo>dist.dir: ${dist.dir}</echo>
+    <echo>dist.library: ${dist.library}</echo>
+    <echo>dist.examples: ${dist.examples}</echo>
+    <echo>dist.doc: ${dist.doc}</echo>
+    <!-- <echo>dist.tld: ${dist.tld}</echo> -->
+    <echo>---------------------------------------------</echo>
+    
+    <!-- Check the build/runtime dependencies -->
+
+    <antcall target="requiredJar">
+       <param name="prop" value="servlet24.jar"/>
+       <param name="file" value="${servlet24.jar}"/>
+       <param name="desc" value="Servlet 2.4 API classes"/>
+    </antcall>
+
+    <antcall target="requiredJar">
+       <param name="prop" value="jsp20.jar"/>
+       <param name="file" value="${jsp20.jar}"/>
+       <param name="desc" value="JSP 2.0 API classes"/>
+    </antcall>
+
+    <antcall target="processIfPropSet">
+       <param name="prop" value="jdbc2_0-stdext.jar"/>
+       <param name="task" value="requiredJarIfPropSet"/>
+       <param name="file" value="${jdbc2_0-stdext.jar}"/>
+       <param name="desc" value="Sun JDBC 2.0 API classes"/>
+    </antcall>
+
+    <antcall target="processIfPropSet">
+       <param name="prop" value="jaxp-api.jar"/>
+       <param name="task" value="requiredJarIfPropSet"/>
+       <param name="file" value="${jaxp-api.jar}"/>
+       <param name="desc" value="JAXP 1.2 API classes"/>
+    </antcall>
+
+    <antcall target="processIfPropSet">
+       <param name="prop" value="dom.jar"/>
+       <param name="task" value="requiredJarIfPropSet"/>
+       <param name="file" value="${dom.jar}"/>
+       <param name="desc" value="JAXP 1.2 DOM API classes"/>
+    </antcall>
+
+    <antcall target="processIfPropSet">
+       <param name="prop" value="sax.jar"/>
+       <param name="task" value="requiredJarIfPropSet"/>
+       <param name="file" value="${sax.jar}"/>
+       <param name="desc" value="JAXP 1.2 SAX API classes"/>
+    </antcall>
+
+    <antcall target="processIfPropSet">
+       <param name="prop" value="xalan.jar"/>
+       <param name="task" value="requiredJarIfPropSet"/>
+       <param name="file" value="${xalan.jar}"/>
+       <param name="desc" value="Xalan implementation"/>
+    </antcall>
+
+    <antcall target="processIfPropSet">
+       <param name="prop" value="xercesImpl.jar"/>
+       <param name="task" value="requiredJarIfPropSet"/>
+       <param name="file" value="${xercesImpl.jar}"/>
+       <param name="desc" value="Xerces implementation"/>
+    </antcall>
+    
+  </target>
+
+  <!-- Set up build directories -->
+  <target name="prepare-build" depends="prepare-dependencies">
+    <mkdir dir="${build.dir}"/>
+    <mkdir dir="${build.library}"/>
+    <mkdir dir="${build.library}/META-INF"/>
+    <mkdir dir="${build.library}/classes"/>
+    <mkdir dir="${build.library}/lib"/>
+    <mkdir dir="${build.examples}"/>
+    <mkdir dir="${build.examples}/WEB-INF"/>
+    <mkdir dir="${build.examples}/WEB-INF/classes"/>
+    <mkdir dir="${build.examples}/WEB-INF/lib"/>
+    <mkdir dir="${build.doc}"/>
+    <mkdir dir="${build.doc}/WEB-INF"/>
+  </target>
+
+  <!-- Set up distribution directory -->
+  <target name="prepare-dist" depends="prepare-build">
+    <mkdir dir="${dist.dir}"/>
+    <mkdir dir="${dist.library}"/>
+    <mkdir dir="${dist.library}/lib"/>
+    <mkdir dir="${dist.library}/tld"/>
+    <mkdir dir="${dist.library}/javadoc"/>
+  </target>
+
+  <!-- =================================================================== -->
+  <!-- Build Tag Library Components                                      -->
+  <!-- =================================================================== -->
+
+  <target name="build" depends="library-build, examples-build, documentation-build"/>
+
+  <!-- Build the tag library itself -->
+  <target name="library-build" depends="prepare-build">  
+    
+    <!-- Compile the taglib.
+         Need to override xalan classes if using J2SE 1.4, that's why we
+         use bootclasspath. Works with J2SE 1.3 as well. -->
+    <javac 
+      srcdir="${library.src}" 
+      destdir="${build.library}/classes"
+      bootclasspath="${xalan.jar}:${java.home}/lib/rt.jar"
+      classpath="${servlet24.jar}:${jsp20.jar}:${jdbc2_0-stdext.jar}:${jaxp-api.jar}:${dom.jar}:${sax.jar}"
+      excludes="org/apache/taglibs/standard/lang/jstl/parser/jsp20/* org/apache/taglibs/standard/lang/jpath/** org/apache/taglibs/standard/lang/spel/**"
+      debug="${compile.debug}"
+      deprecation="${compile.deprecation}"
+      optimize="${compile.optimize}"/> 
+      
+    <!-- copy the TLDs in META-INF -->
+    <copy todir="${build.library}/META-INF">
+      <fileset dir="conf" includes="*.tld"/>
+    </copy>    
+
+    <!-- Copy the resource properties files -->
+    <copy todir="${build.library}/classes">
+      <fileset dir="${library.src}">
+	<include name="**/*.properties"/>
+      </fileset>
+    </copy>
+    
+    <!-- Create the JSTL API jar -->
+    <jar jarfile="${build.library}/lib/jstl.jar"
+         basedir="${build.library}/classes"
+         includes="javax/**">
+      <manifest>
+        <attribute name="Specification-Title" value="JavaServer Pages Standard Tag Library (JSTL)"/>
+        <attribute name="Specification-Version" value="1.1"/>
+        <attribute name="Implementation-Title" value="JavaServer Pages Standard Tag Library API Reference Implementation"/>
+        <attribute name="Implementation-Version" value="${standard-version}"/>
+        <attribute name="Implementation-Vendor" value="Sun Microsystems, Inc."/>
+        <attribute name="Implementation-Vendor-Id" value="com.sun"/>
+        <attribute name="Extension-Name" value="javax.servlet.jsp.jstl"/>
+      </manifest>         
+    </jar>        
+    
+    <!-- Create the implementation jar -->
+    <jar jarfile="${build.library}/lib/standard.jar">
+      <fileset dir="${build.library}/classes">
+        <include name="org/**"/>
+      </fileset>
+      <fileset dir="${build.library}">
+        <include name="META-INF/*.tld"/>
+      </fileset>
+      <manifest>
+        <attribute name="Specification-Title" value="JavaServer Pages Standard Tag Library (JSTL)"/>
+        <attribute name="Specification-Version" value="1.1"/>
+        <attribute name="Implementation-Title" value="jakarta-taglibs 'standard': an implementation of JSTL"/>
+        <attribute name="Implementation-Version" value="${standard-version}"/>
+        <attribute name="Implementation-Vendor" value="Apache Software Foundation"/>
+        <attribute name="Implementation-Vendor-Id" value="org.apache"/>
+        <attribute name="Extension-Name" value="org.apache.taglibs.standard"/>
+      </manifest>         
+    </jar>        
+    
+    <!-- All jar files required at runtime are copied in the 'lib' dir -->
+     
+    <antcall target="processIfPropSet">
+      <param name="prop" value="jdbc2_0-stdext.jar"/>
+      <param name="task" value="copyIfPropSet"/>
+      <param name="file" value="${jdbc2_0-stdext.jar}"/>
+      <param name="todir" value="${build.library}/lib/old-dependencies"/>
+    </antcall>
+
+    <antcall target="processIfPropSet">
+      <param name="prop" value="jaxp-api.jar"/>
+      <param name="task" value="copyIfPropSet"/>
+      <param name="file" value="${jaxp-api.jar}"/>
+      <param name="todir" value="${build.library}/lib/old-dependencies"/>
+    </antcall>
+
+    <antcall target="processIfPropSet">
+      <param name="prop" value="dom.jar"/>
+      <param name="task" value="copyIfPropSet"/>
+      <param name="file" value="${dom.jar}"/>
+      <param name="todir" value="${build.library}/lib/old-dependencies"/>
+    </antcall>
+
+    <antcall target="processIfPropSet">
+      <param name="prop" value="sax.jar"/>
+      <param name="task" value="copyIfPropSet"/>
+      <param name="file" value="${sax.jar}"/>
+      <param name="todir" value="${build.library}/lib/old-dependencies"/>
+    </antcall>
+           
+    <antcall target="processIfPropSet">
+      <param name="prop" value="xalan.jar"/>
+      <param name="task" value="copyIfPropSet"/>
+      <param name="file" value="${xalan.jar}"/>
+      <param name="todir" value="${build.library}/lib/old-dependencies"/>
+    </antcall>
+
+    <antcall target="processIfPropSet">
+      <param name="prop" value="xercesImpl.jar"/>
+      <param name="task" value="copyIfPropSet"/>
+      <param name="file" value="${xercesImpl.jar}"/>
+      <param name="todir" value="${build.library}/lib/old-dependencies"/>
+    </antcall>
+
+  </target>
+
+  <!-- Compile the examples application -->
+  <target name="examples-build" depends="library-build">
+
+    <!-- Compile the examples source code -->
+    <javac srcdir="${examples.src}" destdir="${build.examples}/WEB-INF/classes"
+           classpath="${servlet24.jar}:${jsp20.jar}:${build.library}/classes"
+           debug="${compile.debug}"
+           deprecation="${compile.deprecation}"
+           optimize="${compile.optimize}"/>
+  
+    <!-- Copy web.xml + examples TLD -->
+    <copy todir="${build.examples}/WEB-INF">
+      <fileset dir="${examples.src}/web/WEB-INF"/>
+    </copy>
+    
+    <!-- Copy web pages -->
+    <copy todir="${build.examples}">
+      <fileset dir="${examples.src}/web"/>
+    </copy>
+        
+    <!-- copy the runtime jar files -->
+    <copy todir="${build.examples}/WEB-INF/lib">
+      <fileset dir="${build.library}/lib" includes="*.jar"/>
+    </copy>
+    
+  </target>
+
+  <!-- Compile the documentation application -->
+  <target name="documentation-build" depends="prepare-build">
+  
+    <copy todir="${build.doc}/WEB-INF">
+      <fileset dir="${doc.src}/conf"/>
+    </copy>
+    
+    <copy todir="${build.doc}">
+      <fileset dir="${doc.src}/web">
+        <include name="**/*.html"/>
+      </fileset>
+    </copy>    
+  </target>
+  
+  <!-- =================================================================== -->
+  <!-- Create the Distribution                                             -->
+  <!-- =================================================================== -->
+
+  <!-- Create the entire set of distribution files -->
+  <target name="dist" depends="library-dist,examples-dist,documentation-dist,javadoc-dist"/>
+
+  <!-- Create the library distribution files -->
+  <target name="library-dist" depends="library-build, prepare-dist">
+
+    <!-- Copy the runtime jar files -->
+    <copy todir="${dist.library}/lib">
+      <fileset dir="${build.library}/lib" includes="**/*.jar"/>
+    </copy>
+
+    <!-- All TLDs are copied in the 'tld' dir of the distribution -->
+    <copy todir="${dist.dir}/${taglib.name}/tld">
+      <fileset dir="${conf.src}" includes="*.tld"/>
+    </copy>
+      
+    <!-- LICENSE and NOTICE files copied at the top level of the distribution -->
+    <copy file="../LICENSE" tofile="${dist.library}/LICENSE"/>
+    <copy file="../NOTICE" tofile="${dist.library}/NOTICE"/>
+
+    <!-- README file copied at the top level of the distribution -->
+    <copy file="README_bin.txt" tofile="${dist.library}/README"/>
+    
+  </target>
+
+  <!-- Create the examples application WAR file -->
+  <target name="examples-dist" depends="examples-build, prepare-dist">    
+      <!-- create the jar for the examples webapp -->  
+      <jar jarfile="${dist.examples}" basedir="${build.examples}"/>
+  </target>
+
+  <!-- Create the documentation application WAR file -->
+  <target name="documentation-dist" depends="documentation-build, prepare-dist">
+      <jar jarfile="${dist.doc}" basedir="${build.doc}" excludes="intro.html"/>
+      <mkdir dir="${taglibs.doc}"/>
+      <copy todir="${taglibs.doc}">
+          <fileset dir="${build.doc}">
+              <exclude name="WEB-INF/**"/>
+          </fileset>
+      </copy>
+  </target>
+  
+  <!-- Create the javadocs -->
+  <target name="javadoc-dist" depends="prepare-dist">
+   <javadoc packagenames="javax.servlet.jsp.jstl.*"
+            sourcepath="src"
+            classpath="${servlet24.jar}:${jsp20.jar}:${jdbc2_0-stdext.jar}:${jaxp-api.jar}:${dom.jar}:${sax.jar}:${xercesImpl.jar}:${xalan.jar}"
+            destdir="${dist.library}/javadoc"
+            bottom='<font size="-1">Copyright 2003 Sun Microsystems, Inc. All Rights Reserved.</font>'/>
+  </target>
+
+  <!-- =================================================================== -->
+  <!-- Nightly (components generated for the website)                      -->
+  <!-- =================================================================== -->
+  
+  <target name="dist-nightly" depends="dist">
+    <!-- website intro page for the taglib -->
+    <style in="${xml.src}/intro.xml"
+           destdir="${build.doc}"                                          
+           out="${build.doc}/intro.html"
+           style="${taglibs.xsl}">
+      <param name="prefix" expression="../../"/>
+    </style>
+    <copy file="${build.doc}/intro.html" todir="${taglibs.doc}"/>
+  </target>    
+  
+  <!-- =================================================================== -->
+  <!-- Public utility targets                                              -->
+  <!-- =================================================================== -->
+ 
+  <!-- Delete build and dist directories so we can start from scratch -->
+  <target name="clean">
+    <delete dir="${build.dir}/${taglib.name}"/>
+    <delete dir="${dist.dir}/${taglib.name}"/>
+  </target>
+
+  <!-- =================================================================== -->
+  <!-- Private utility targets                                              -->
+  <!-- =================================================================== -->
+  
+  <!-- Check the availability of a required jar -->
+  <target name="requiredJar">
+    <echo message="  ${prop}"/>
+    <available file="${file}" property="requirement.satisfied"/>
+    <antcall target="requiredJarFailed"/>
+  </target>
+
+  <!-- Support for target 'requiredJar' -->
+  <target name="requiredJarFailed" unless="requirement.satisfied">
+    <echo message="The property ${prop} must be set to a jar file containing"/>
+    <echo message="the '${desc}'."/>
+    <fail message="Current value for ${prop} is: ${file}."/>
+  </target>
+  
+  <!-- Process a target only if a property is set.
+       Allows us to ignore some dependencies that are included in
+       J2SE 1.4 but were not prior to that. -->
+  <target name="processIfPropSet">
+    <echo message="  ${prop}"/>
+    <condition property="prop.specified">
+      <isSet property="${prop}"/>
+    </condition>
+    <antcall target="${task}"/>
+    <antcall target="${task}Not"/>
+  </target>
+
+  <!-- Check the availability of a required jar only if property is set -->
+  <target name="requiredJarIfPropSet" if="prop.specified">
+    <antcall target="requiredJar"/>
+  </target>
+
+  <!-- Warning message when required jar is ignored because the property
+       is not set. -->
+  <target name="requiredJarIfPropSetNot" unless="prop.specified">
+    <echo message="  Ignoring dependency on ${prop} because property is not set."/>
+    <echo message="  OK as long as both compile and run-time environments are at least J2SE 1.4."/>
+  </target>
+
+  <!-- Copy file only if property is set -->
+  <target name="copyIfPropSet" if="prop.specified">
+    <copy file="${file}" todir="${todir}"/>
+  </target>
+
+  <!-- Warning message when file is not copied because the property
+       is not set. -->
+  <target name="copyIfPropSetNot" unless="prop.specified">
+    <echo message="  Ignoring copy of ${prop} because property is not set."/>
+  </target>  
+
+  <!-- =================================================================== -->
+  <!-- Perform an official release -->
+  <!-- =================================================================== -->
+  <target name="release" depends="dist">
+    <mkdir dir="${release.dir}"/>
+    <antcall target="${release.pre}"/>
+    <!-- Copy the taglib to the release dir -->
+    <copy todir="${release.dir}" >
+      <fileset dir="${dist.dir}/${taglib.name}" excludes="doc/**"/>
+    </copy>
+    <copy file="../LICENSE"   tofile="${release.dir}/LICENSE"/>
+    <copy file="../NOTICE"    tofile="${release.dir}/NOTICE"/>
+    <copy file="../README"    tofile="${release.dir}/README"/>
+    <zip zipfile="${dist.dir}/${release.name}.zip"
+       basedir="${dist.dir}" includes="${release.name}/**"/>
+    <tar tarfile="${dist.dir}/${release.name}.tar"
+       basedir="${dist.dir}" includes="${release.name}/**"/>
+    <gzip zipfile="${dist.dir}/${release.name}.tar.gz"
+          src="${dist.dir}/${release.name}.tar"/>
+    <delete dir="${dist.dir}/${release.name}"/> 
+    <delete file="${dist.dir}/${release.name}.tar"/> 
+    <antcall target="${release.post}"/>
+  </target>
+
+  <!-- target that does nothing -->
+  <target name="nop"/>
+
+  <!-- =================================================================== -->
+  <!-- Unit Test PassThru Targets -->
+  <!-- =================================================================== -->
+  <target name="test" depends="build">
+    <ant antfile="build-tests.xml" target="run.test"/>
+  </target>
+
+  <target name="run.cactus" depends="build">
+    <ant antfile="build-tests.xml" target="run.cactus"/>
+  </target>
+
+  <target name="run.junit" depends="build">
+    <ant antfile="build-tests.xml" target="junit"/>
+  </target>
+
+</project>
diff --git a/standard/build_sample_standard.properties b/standard/build_sample_standard.properties
new file mode 100644
index 0000000..9fb2e33
--- /dev/null
+++ b/standard/build_sample_standard.properties
@@ -0,0 +1,80 @@
+# Sample build.properties bundled with a standalone (i.e. without all the
+# other jakarta-taglibs taglibs) source distribution of the
+# standard tag library. If building from a full source distribution
+# of jakarta-taglibs, properties mus be set in jakarta-taglibs/build.properties.
+
+# The base directory of your jakarta-taglibs-standard distribution
+
+base.dir=${user.home}/jakarta-taglibs-standard
+build.dir = ${base.dir}/build
+build.classes=${build.dir}/standard/standard/classes
+dist.dir = ${base.dir}/dist
+
+# Servlet 2.4 and JSP 2.0
+
+servlet24.jar=
+jsp20.jar=
+
+# Standard (JSTL RI) and dbtags require the
+# JDBC 2.0 Standard Extensions
+# {No need to specify if using J2SE 1.4.2 or higher)
+
+#jdbc2_0-stdext.jar=
+
+# JAXP 1.2
+# {No need to specify if using J2SE 1.4.2 or higher)
+# {NOTE: J2SE 5.0 uses JAXP 1.3 so you will need to specify}
+
+#jaxp-api.jar=
+#dom.jar=
+#sax.jar=
+#xercesImpl.jar=
+
+# Xalan
+# {No need to specify if using J2SE 1.4.2 or higher)
+# {NOTE: J2SE 5.0 uses JAXP 1.3 so you will need to specify}
+
+#xalan.jar=
+
+
+# ----- Run Control Flags -----
+
+# Define the arguments to give to the jvm to enable debugging
+# If this is commented out, no debugging arguments will be passed.
+# Make sure to uncomment the proper arguments for your platform.
+
+# ----- Unix
+#debug.jvm.args = -Xdebug -Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=n
+
+# ----- Windows
+#debug.jvm.args = -Xdebug -Xrunjdwp:transport=dt_shmem,address=jdbconn,server=y,suspend=n
+
+# ----- Compile Control Flags -----
+
+compile.deprecation = true
+compile.debug = true
+compile.optimize = false
+
+# --------------------------------------------------
+#   REQUIRED LIBRARIES FOR UNIT TESTS
+# --------------------------------------------------
+jstl.jar=${build.dir}/standard/standard/lib/jstl.jar
+standard.jar=${build.dir}/standard/standard/lib/standard.jar
+junit.jar=
+
+cactus.home=
+cactus.jar=${cactus.home}/lib/cactus-1.6.1.jar
+cactus.ant.jar=${cactus.home}/lib/cactus-ant-1.6.1.jar
+aspectjrt.jar=${cactus.home}/lib/aspectjrt-1.1.1.jar
+httpclient.jar=${cactus.home}/lib/commons-httpclient-2.0.jar
+commons-logging.jar=${cactus.home}/lib/commons-logging-1.0.3.jar
+
+# --------------------------------------------------
+#   RUN-TIME COMPONENTS FOR UNIT TESTS
+# --------------------------------------------------
+tomcat.home=
+tomcat.webapps=${tomcat.home}/webapps
+username=tomcat
+password=tomcat
+web.server.host=localhost
+web.server.port=8080
diff --git a/standard/conf/c-1_0-rt.tld b/standard/conf/c-1_0-rt.tld
new file mode 100644
index 0000000..2203657
--- /dev/null
+++ b/standard/conf/c-1_0-rt.tld
@@ -0,0 +1,393 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE taglib
+  PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
+  "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
+<taglib>
+  <tlib-version>1.0</tlib-version>
+  <jsp-version>1.2</jsp-version>
+  <short-name>c_rt</short-name>
+  <uri>http://java.sun.com/jstl/core_rt</uri>
+  <display-name>JSTL core RT</display-name>
+  <description>JSTL 1.0 core library</description>
+
+  <validator>
+    <validator-class>
+        org.apache.taglibs.standard.tlv.JstlCoreTLV
+    </validator-class>
+    <description>
+        Provides core validation features for JSTL tags.
+    </description>
+  </validator>
+
+  <tag>
+    <name>catch</name>
+    <tag-class>org.apache.taglibs.standard.tag.common.core.CatchTag</tag-class>
+    <body-content>JSP</body-content>
+    <description>
+        Catches any Throwable that occurs in its body and optionally
+        exposes it.
+    </description>
+    <attribute>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>choose</name>
+    <tag-class>org.apache.taglibs.standard.tag.common.core.ChooseTag</tag-class>
+    <body-content>JSP</body-content>
+    <description>
+	Simple conditional tag that establishes a context for
+	mutually exclusive conditional operations, marked by
+	<when> and <otherwise>
+    </description>
+  </tag>
+
+  <tag>
+    <name>if</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.core.IfTag</tag-class>
+    <body-content>JSP</body-content>
+    <description>
+	Simple conditional tag, which evalutes its body if the
+	supplied condition is true and optionally exposes a Boolean
+	scripting variable representing the evaluation of this condition
+    </description>
+    <attribute>
+        <name>test</name>
+        <required>true</required>
+        <rtexprvalue>true</rtexprvalue>
+	<type>boolean</type>
+    </attribute>
+    <attribute>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>import</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.core.ImportTag</tag-class>
+    <tei-class>org.apache.taglibs.standard.tei.ImportTEI</tei-class>
+    <body-content>JSP</body-content>
+    <description>
+        Retrieves an absolute or relative URL and exposes its contents
+        to either the page, a String in 'var', or a Reader in 'varReader'.
+    </description>
+    <attribute>
+        <name>url</name>
+        <required>true</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>varReader</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>context</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>charEncoding</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>forEach</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.core.ForEachTag</tag-class>
+    <tei-class>org.apache.taglibs.standard.tei.ForEachTEI</tei-class>
+    <body-content>JSP</body-content>
+    <description>
+	The basic iteration tag, accepting many different
+        collection types and supporting subsetting and other
+        functionality
+    </description>
+    <attribute>
+	<name>items</name>
+	<required>false</required>
+	<rtexprvalue>true</rtexprvalue>
+	<type>java.lang.Object</type>
+    </attribute>
+    <attribute>
+	<name>begin</name>
+	<required>false</required>
+	<rtexprvalue>true</rtexprvalue>
+	<type>int</type>
+    </attribute>
+    <attribute>
+	<name>end</name>
+	<required>false</required>
+	<rtexprvalue>true</rtexprvalue>
+	<type>int</type>
+    </attribute>
+    <attribute>
+	<name>step</name>
+	<required>false</required>
+	<rtexprvalue>true</rtexprvalue>
+	<type>int</type>
+    </attribute>
+    <attribute>
+	<name>var</name>
+	<required>false</required>
+	<rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+	<name>varStatus</name>
+	<required>false</required>
+	<rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>forTokens</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.core.ForTokensTag</tag-class>
+    <body-content>JSP</body-content>
+    <description>
+	Iterates over tokens, separated by the supplied delimeters
+    </description>
+    <attribute>
+	<name>items</name>
+	<required>true</required>
+	<rtexprvalue>true</rtexprvalue>
+	<type>java.lang.String</type>
+    </attribute>
+    <attribute>
+	<name>delims</name>
+	<required>true</required>
+	<rtexprvalue>true</rtexprvalue>
+	<type>java.lang.String</type>
+    </attribute>
+    <attribute>
+	<name>begin</name>
+	<required>false</required>
+	<rtexprvalue>true</rtexprvalue>
+	<type>int</type>
+    </attribute>
+    <attribute>
+	<name>end</name>
+	<required>false</required>
+	<rtexprvalue>true</rtexprvalue>
+	<type>int</type>
+    </attribute>
+    <attribute>
+	<name>step</name>
+	<required>false</required>
+	<rtexprvalue>true</rtexprvalue>
+	<type>int</type>
+    </attribute>
+    <attribute>
+	<name>var</name>
+	<required>false</required>
+	<rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+	<name>varStatus</name>
+	<required>false</required>
+	<rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>out</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.core.OutTag</tag-class>
+    <body-content>JSP</body-content>
+    <description>
+        Like <%= ... >, but for expressions.
+    </description> 
+    <attribute>
+        <name>value</name>
+        <required>true</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>default</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>escapeXml</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+  </tag>
+
+
+  <tag>
+    <name>otherwise</name>
+    <tag-class>org.apache.taglibs.standard.tag.common.core.OtherwiseTag</tag-class>
+    <body-content>JSP</body-content>
+    <description>
+        Subtag of <choose> that follows <when> tags
+        and runs only if all of the prior conditions evaluated to
+        'false'
+    </description>
+  </tag>
+
+  <tag>
+    <name>param</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.core.ParamTag</tag-class>
+    <body-content>JSP</body-content>
+    <description>
+        Adds a parameter to a containing 'import' tag's URL.
+    </description>
+    <attribute>
+        <name>name</name>
+        <required>true</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>value</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>redirect</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.core.RedirectTag</tag-class>
+    <body-content>JSP</body-content>
+    <description>
+        Redirects to a new URL.
+    </description>
+    <attribute>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>url</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>context</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>remove</name>
+    <tag-class>org.apache.taglibs.standard.tag.common.core.RemoveTag</tag-class>
+    <body-content>empty</body-content>
+    <description>
+        Removes a scoped variable (from a particular scope, if specified).
+    </description>
+    <attribute>
+        <name>var</name>
+        <required>true</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+ <tag>
+    <name>set</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.core.SetTag</tag-class>
+    <body-content>JSP</body-content>
+    <description>
+        Sets the result of an expression evaluation in a 'scope'
+    </description>
+    <attribute>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>value</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>target</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>property</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>url</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.core.UrlTag</tag-class>
+    <body-content>JSP</body-content>
+    <description>
+        Creates a URL with optional query parameters.
+    </description>
+    <attribute>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>value</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>context</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>when</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.core.WhenTag</tag-class>
+    <body-content>JSP</body-content>
+    <description>
+	Subtag of <choose> that includes its body if its
+	condition evalutes to 'true'
+    </description>
+    <attribute>
+        <name>test</name>
+        <required>true</required>
+        <rtexprvalue>true</rtexprvalue>
+	<type>boolean</type>
+    </attribute>
+  </tag>
+
+</taglib>
diff --git a/standard/conf/c-1_0.tld b/standard/conf/c-1_0.tld
new file mode 100644
index 0000000..ce80e8d
--- /dev/null
+++ b/standard/conf/c-1_0.tld
@@ -0,0 +1,416 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE taglib
+  PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
+  "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
+<taglib>
+  <tlib-version>1.0</tlib-version>
+  <jsp-version>1.2</jsp-version>
+  <short-name>c</short-name>
+  <uri>http://java.sun.com/jstl/core</uri>
+  <display-name>JSTL core</display-name>
+  <description>JSTL 1.0 core library</description>
+
+  <validator>
+    <validator-class>
+	org.apache.taglibs.standard.tlv.JstlCoreTLV
+    </validator-class>
+    <init-param>
+	<param-name>expressionAttributes</param-name>
+	<param-value>
+	    out:value
+	    out:default
+	    out:escapeXml
+	    if:test
+	    import:url
+	    import:context
+	    import:charEncoding
+	    forEach:items
+	    forEach:begin
+	    forEach:end
+	    forEach:step
+	    forTokens:items
+	    forTokens:begin
+	    forTokens:end
+	    forTokens:step
+	    param:encode
+	    param:name
+	    param:value
+            redirect:context
+            redirect:url
+	    set:property
+	    set:target
+	    set:value
+	    url:context
+	    url:value
+	    when:test
+	</param-value>
+	<description>
+	    Whitespace-separated list of colon-separated token pairs
+	    describing tag:attribute combinations that accept expressions.
+	    The validator uses this information to determine which
+	    attributes need their syntax validated.
+	</description>
+     </init-param>
+  </validator>
+
+  <tag>
+    <name>catch</name>
+    <tag-class>org.apache.taglibs.standard.tag.common.core.CatchTag</tag-class>
+    <body-content>JSP</body-content>
+    <description>
+        Catches any Throwable that occurs in its body and optionally
+        exposes it.
+    </description>
+    <attribute>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>choose</name>
+    <tag-class>org.apache.taglibs.standard.tag.common.core.ChooseTag</tag-class>
+    <body-content>JSP</body-content>
+    <description>
+        Simple conditional tag that establishes a context for
+        mutually exclusive conditional operations, marked by
+        <when> and <otherwise>
+    </description>
+  </tag>
+
+  <tag>
+    <name>out</name>
+    <tag-class>org.apache.taglibs.standard.tag.el.core.OutTag</tag-class>
+    <body-content>JSP</body-content>
+    <description>
+	Like <%= ... >, but for expressions.
+    </description>
+    <attribute>
+        <name>value</name>
+        <required>true</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>default</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>escapeXml</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>if</name>
+    <tag-class>org.apache.taglibs.standard.tag.el.core.IfTag</tag-class>
+    <body-content>JSP</body-content>
+    <description>
+        Simple conditional tag, which evalutes its body if the
+        supplied condition is true and optionally exposes a Boolean
+        scripting variable representing the evaluation of this condition
+    </description>
+    <attribute>
+        <name>test</name>
+        <required>true</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>import</name>
+    <tag-class>org.apache.taglibs.standard.tag.el.core.ImportTag</tag-class>
+    <tei-class>org.apache.taglibs.standard.tei.ImportTEI</tei-class>
+    <body-content>JSP</body-content>
+    <description>
+	Retrieves an absolute or relative URL and exposes its contents
+	to either the page, a String in 'var', or a Reader in 'varReader'.
+    </description>
+    <attribute>
+        <name>url</name>
+        <required>true</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>varReader</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>context</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>charEncoding</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>forEach</name>
+    <tag-class>org.apache.taglibs.standard.tag.el.core.ForEachTag</tag-class>
+    <tei-class>org.apache.taglibs.standard.tei.ForEachTEI</tei-class>
+    <body-content>JSP</body-content>
+    <description>
+	The basic iteration tag, accepting many different
+        collection types and supporting subsetting and other
+        functionality
+    </description>
+    <attribute>
+	<name>items</name>
+	<required>false</required>
+	<rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+	<name>begin</name>
+	<required>false</required>
+	<rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+	<name>end</name>
+	<required>false</required>
+	<rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+	<name>step</name>
+	<required>false</required>
+	<rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+	<name>var</name>
+	<required>false</required>
+	<rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+	<name>varStatus</name>
+	<required>false</required>
+	<rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>forTokens</name>
+    <tag-class>org.apache.taglibs.standard.tag.el.core.ForTokensTag</tag-class>
+    <body-content>JSP</body-content>
+    <description>
+	Iterates over tokens, separated by the supplied delimeters
+    </description>
+    <attribute>
+	<name>items</name>
+	<required>true</required>
+	<rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+	<name>delims</name>
+	<required>true</required>
+	<rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+	<name>begin</name>
+	<required>false</required>
+	<rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+	<name>end</name>
+	<required>false</required>
+	<rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+	<name>step</name>
+	<required>false</required>
+	<rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+	<name>var</name>
+	<required>false</required>
+	<rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+	<name>varStatus</name>
+	<required>false</required>
+	<rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>otherwise</name>
+    <tag-class>org.apache.taglibs.standard.tag.common.core.OtherwiseTag</tag-class>
+    <body-content>JSP</body-content>
+    <description>
+	Subtag of <choose> that follows <when> tags
+	and runs only if all of the prior conditions evaluated to
+	'false'
+    </description>
+  </tag>
+
+  <tag>
+    <name>param</name>
+    <tag-class>org.apache.taglibs.standard.tag.el.core.ParamTag</tag-class>
+    <body-content>JSP</body-content>
+    <description>
+	Adds a parameter to a containing 'import' tag's URL.
+    </description>
+    <attribute>
+        <name>name</name>
+        <required>true</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>value</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>redirect</name>
+    <tag-class>org.apache.taglibs.standard.tag.el.core.RedirectTag</tag-class>
+    <body-content>JSP</body-content>
+    <description>
+	Redirects to a new URL.
+    </description>
+    <attribute>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>url</name>
+        <required>true</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>context</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>remove</name>
+    <tag-class>org.apache.taglibs.standard.tag.common.core.RemoveTag</tag-class>
+    <body-content>empty</body-content>
+    <description>
+	Removes a scoped variable (from a particular scope, if specified).
+    </description>
+    <attribute>
+        <name>var</name>
+        <required>true</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>set</name>
+    <tag-class>org.apache.taglibs.standard.tag.el.core.SetTag</tag-class>
+    <body-content>JSP</body-content>
+    <description>
+	Sets the result of an expression evaluation in a 'scope'
+    </description>
+    <attribute>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>value</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>target</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>property</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>url</name>
+    <tag-class>org.apache.taglibs.standard.tag.el.core.UrlTag</tag-class>
+    <body-content>JSP</body-content>
+    <description>
+	Prints or exposes a URL with optional query parameters
+        (via the c:param tag).
+    </description>
+    <attribute>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>value</name>
+        <required>true</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>context</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>when</name>
+    <tag-class>org.apache.taglibs.standard.tag.el.core.WhenTag</tag-class>
+    <body-content>JSP</body-content>
+    <description>
+        Subtag of <choose> that includes its body if its
+        condition evalutes to 'true'
+    </description>
+    <attribute>
+        <name>test</name>
+        <required>true</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+</taglib>
diff --git a/standard/conf/c.tld b/standard/conf/c.tld
new file mode 100644
index 0000000..22698c9
--- /dev/null
+++ b/standard/conf/c.tld
@@ -0,0 +1,563 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
+    version="2.0">
+    
+  <description>JSTL 1.1 core library</description>
+  <display-name>JSTL core</display-name>
+  <tlib-version>1.1</tlib-version>
+  <short-name>c</short-name>
+  <uri>http://java.sun.com/jsp/jstl/core</uri>
+
+  <validator>
+    <description>
+        Provides core validation features for JSTL tags.
+    </description>
+    <validator-class>
+        org.apache.taglibs.standard.tlv.JstlCoreTLV
+    </validator-class>
+  </validator>
+
+  <tag>
+    <description>
+        Catches any Throwable that occurs in its body and optionally
+        exposes it.
+    </description>
+    <name>catch</name>
+    <tag-class>org.apache.taglibs.standard.tag.common.core.CatchTag</tag-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <description>
+Name of the exported scoped variable for the
+exception thrown from a nested action. The type of the
+scoped variable is the type of the exception thrown.
+        </description>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+	Simple conditional tag that establishes a context for
+	mutually exclusive conditional operations, marked by
+	<when> and <otherwise>
+    </description>
+    <name>choose</name>
+    <tag-class>org.apache.taglibs.standard.tag.common.core.ChooseTag</tag-class>
+    <body-content>JSP</body-content>
+  </tag>
+
+  <tag>
+    <description>
+	Simple conditional tag, which evalutes its body if the
+	supplied condition is true and optionally exposes a Boolean
+	scripting variable representing the evaluation of this condition
+    </description>
+    <name>if</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.core.IfTag</tag-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <description>
+The test condition that determines whether or
+not the body content should be processed.
+        </description>
+        <name>test</name>
+        <required>true</required>
+        <rtexprvalue>true</rtexprvalue>
+	<type>boolean</type>
+    </attribute>
+    <attribute>
+        <description>
+Name of the exported scoped variable for the
+resulting value of the test condition. The type
+of the scoped variable is Boolean.        
+        </description>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Scope for var.
+        </description>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+        Retrieves an absolute or relative URL and exposes its contents
+        to either the page, a String in 'var', or a Reader in 'varReader'.
+    </description>
+    <name>import</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.core.ImportTag</tag-class>
+    <tei-class>org.apache.taglibs.standard.tei.ImportTEI</tei-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <description>
+The URL of the resource to import.
+        </description>
+        <name>url</name>
+        <required>true</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Name of the exported scoped variable for the
+resource's content. The type of the scoped
+variable is String.
+        </description>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Scope for var.
+        </description>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Name of the exported scoped variable for the
+resource's content. The type of the scoped
+variable is Reader.
+        </description>
+        <name>varReader</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Name of the context when accessing a relative
+URL resource that belongs to a foreign
+context.
+        </description>
+        <name>context</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Character encoding of the content at the input
+resource.
+        </description>
+        <name>charEncoding</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+	The basic iteration tag, accepting many different
+        collection types and supporting subsetting and other
+        functionality
+    </description>
+    <name>forEach</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.core.ForEachTag</tag-class>
+    <tei-class>org.apache.taglibs.standard.tei.ForEachTEI</tei-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <description>
+Collection of items to iterate over.
+        </description>
+	<name>items</name>
+	<required>false</required>
+	<rtexprvalue>true</rtexprvalue>
+	<type>java.lang.Object</type>
+    </attribute>
+    <attribute>
+        <description>
+If items specified:
+Iteration begins at the item located at the
+specified index. First item of the collection has
+index 0.
+If items not specified:
+Iteration begins with index set at the value
+specified.
+        </description>
+	<name>begin</name>
+	<required>false</required>
+	<rtexprvalue>true</rtexprvalue>
+	<type>int</type>
+    </attribute>
+    <attribute>
+        <description>
+If items specified:
+Iteration ends at the item located at the
+specified index (inclusive).
+If items not specified:
+Iteration ends when index reaches the value
+specified.
+        </description>
+	<name>end</name>
+	<required>false</required>
+	<rtexprvalue>true</rtexprvalue>
+	<type>int</type>
+    </attribute>
+    <attribute>
+        <description>
+Iteration will only process every step items of
+the collection, starting with the first one.
+        </description>
+	<name>step</name>
+	<required>false</required>
+	<rtexprvalue>true</rtexprvalue>
+	<type>int</type>
+    </attribute>
+    <attribute>
+        <description>
+Name of the exported scoped variable for the
+current item of the iteration. This scoped
+variable has nested visibility. Its type depends
+on the object of the underlying collection.
+        </description>
+	<name>var</name>
+	<required>false</required>
+	<rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Name of the exported scoped variable for the
+status of the iteration. Object exported is of type
+javax.servlet.jsp.jstl.core.LoopTagStatus. This scoped variable has nested
+visibility.
+        </description>
+	<name>varStatus</name>
+	<required>false</required>
+	<rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+	Iterates over tokens, separated by the supplied delimeters
+    </description>
+    <name>forTokens</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.core.ForTokensTag</tag-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <description>
+String of tokens to iterate over.
+        </description>
+	<name>items</name>
+	<required>true</required>
+	<rtexprvalue>true</rtexprvalue>
+	<type>java.lang.String</type>
+    </attribute>
+    <attribute>
+        <description>
+The set of delimiters (the characters that
+separate the tokens in the string).
+        </description>
+	<name>delims</name>
+	<required>true</required>
+	<rtexprvalue>true</rtexprvalue>
+	<type>java.lang.String</type>
+    </attribute>
+    <attribute>
+        <description>
+Iteration begins at the token located at the
+specified index. First token has index 0.
+        </description>
+	<name>begin</name>
+	<required>false</required>
+	<rtexprvalue>true</rtexprvalue>
+	<type>int</type>
+    </attribute>
+    <attribute>
+        <description>
+Iteration ends at the token located at the
+specified index (inclusive).
+        </description>
+	<name>end</name>
+	<required>false</required>
+	<rtexprvalue>true</rtexprvalue>
+	<type>int</type>
+    </attribute>
+    <attribute>
+        <description>
+Iteration will only process every step tokens
+of the string, starting with the first one.
+        </description>
+	<name>step</name>
+	<required>false</required>
+	<rtexprvalue>true</rtexprvalue>
+	<type>int</type>
+    </attribute>
+    <attribute>
+        <description>
+Name of the exported scoped variable for the
+current item of the iteration. This scoped
+variable has nested visibility.
+        </description>
+	<name>var</name>
+	<required>false</required>
+	<rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Name of the exported scoped variable for the
+status of the iteration. Object exported is of
+type
+javax.servlet.jsp.jstl.core.LoopTag
+Status. This scoped variable has nested
+visibility.
+        </description>
+	<name>varStatus</name>
+	<required>false</required>
+	<rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+        Like <%= ... >, but for expressions.
+    </description> 
+    <name>out</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.core.OutTag</tag-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <description>
+Expression to be evaluated.
+        </description>
+        <name>value</name>
+        <required>true</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Default value if the resulting value is null.
+        </description>
+        <name>default</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Determines whether characters <,>,&,'," in the
+resulting string should be converted to their
+corresponding character entity codes. Default value is
+true.
+        </description>
+        <name>escapeXml</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+  </tag>
+
+
+  <tag>
+    <description>
+        Subtag of <choose> that follows <when> tags
+        and runs only if all of the prior conditions evaluated to
+        'false'
+    </description>
+    <name>otherwise</name>
+    <tag-class>org.apache.taglibs.standard.tag.common.core.OtherwiseTag</tag-class>
+    <body-content>JSP</body-content>
+  </tag>
+
+  <tag>
+    <description>
+        Adds a parameter to a containing 'import' tag's URL.
+    </description>
+    <name>param</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.core.ParamTag</tag-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <description>
+Name of the query string parameter.
+        </description>
+        <name>name</name>
+        <required>true</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Value of the parameter.
+        </description>
+        <name>value</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+        Redirects to a new URL.
+    </description>
+    <name>redirect</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.core.RedirectTag</tag-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <description>
+The URL of the resource to redirect to.
+        </description>
+        <name>url</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Name of the context when redirecting to a relative URL
+resource that belongs to a foreign context.
+        </description>
+        <name>context</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+        Removes a scoped variable (from a particular scope, if specified).
+    </description>
+    <name>remove</name>
+    <tag-class>org.apache.taglibs.standard.tag.common.core.RemoveTag</tag-class>
+    <body-content>empty</body-content>
+    <attribute>
+        <description>
+Name of the scoped variable to be removed.
+        </description>
+        <name>var</name>
+        <required>true</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Scope for var.
+        </description>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+ <tag>
+    <description>
+        Sets the result of an expression evaluation in a 'scope'
+    </description>
+    <name>set</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.core.SetTag</tag-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <description>
+Name of the exported scoped variable to hold the value
+specified in the action. The type of the scoped variable is
+whatever type the value expression evaluates to.
+        </description>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Expression to be evaluated.
+        </description>
+        <name>value</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Target object whose property will be set. Must evaluate to
+a JavaBeans object with setter property property, or to a
+java.util.Map object.
+        </description>
+        <name>target</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Name of the property to be set in the target object.
+        </description>
+        <name>property</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Scope for var.
+        </description>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+        Creates a URL with optional query parameters.
+    </description>
+    <name>url</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.core.UrlTag</tag-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <description>
+Name of the exported scoped variable for the
+processed url. The type of the scoped variable is
+String.
+        </description>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Scope for var.
+        </description>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+URL to be processed.
+        </description>
+        <name>value</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Name of the context when specifying a relative URL
+resource that belongs to a foreign context.
+        </description>
+        <name>context</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+	Subtag of <choose> that includes its body if its
+	condition evalutes to 'true'
+    </description>
+    <name>when</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.core.WhenTag</tag-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <description>
+The test condition that determines whether or not the
+body content should be processed.
+        </description>
+        <name>test</name>
+        <required>true</required>
+        <rtexprvalue>true</rtexprvalue>
+	<type>boolean</type>
+    </attribute>
+  </tag>
+
+</taglib>
diff --git a/standard/conf/fmt-1_0-rt.tld b/standard/conf/fmt-1_0-rt.tld
new file mode 100644
index 0000000..45d1545
--- /dev/null
+++ b/standard/conf/fmt-1_0-rt.tld
@@ -0,0 +1,403 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE taglib
+  PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
+  "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
+<taglib>
+  <tlib-version>1.0</tlib-version>
+  <jsp-version>1.2</jsp-version>
+  <short-name>fmt_rt</short-name>
+  <uri>http://java.sun.com/jstl/fmt_rt</uri>
+  <display-name>JSTL fmt RT</display-name>
+  <description>JSTL 1.0 i18n-capable formatting library</description>
+
+  <validator>
+    <validator-class>
+        org.apache.taglibs.standard.tlv.JstlFmtTLV
+    </validator-class>
+    <description>
+        Provides core validation features for JSTL tags.
+    </description>
+  </validator>
+
+  <tag>
+    <name>requestEncoding</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.fmt.RequestEncodingTag</tag-class>
+    <body-content>empty</body-content>
+    <description>
+        Sets the request character encoding
+    </description>
+    <attribute>
+        <name>value</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>setLocale</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.fmt.SetLocaleTag</tag-class>
+    <body-content>empty</body-content>
+    <description>
+        Stores the given locale in the locale configuration variable
+    </description>
+    <attribute>
+        <name>value</name>
+        <required>true</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>variant</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>timeZone</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.fmt.TimeZoneTag</tag-class>
+    <body-content>JSP</body-content>
+    <description>
+        Specifies the time zone for any time formatting or parsing actions
+        nested in its body
+    </description>
+    <attribute>
+        <name>value</name>
+        <required>true</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>setTimeZone</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.fmt.SetTimeZoneTag</tag-class>
+    <body-content>empty</body-content>
+    <description>
+        Stores the given time zone in the time zone configuration variable
+    </description>
+    <attribute>
+        <name>value</name>
+        <required>true</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>bundle</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.fmt.BundleTag</tag-class>
+    <body-content>JSP</body-content>
+    <description>
+        Loads a resource bundle to be used by its tag body
+    </description>
+    <attribute>
+        <name>basename</name>
+        <required>true</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>prefix</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>setBundle</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.fmt.SetBundleTag</tag-class>
+    <body-content>empty</body-content>
+    <description>
+        Loads a resource bundle and stores it in the named scoped variable or
+        the bundle configuration variable
+    </description>
+    <attribute>
+        <name>basename</name>
+        <required>true</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>message</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.fmt.MessageTag</tag-class>
+    <body-content>JSP</body-content>
+    <description>
+        Maps key to localized message and performs parametric replacement
+    </description>
+    <attribute>
+        <name>key</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>bundle</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>param</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.fmt.ParamTag</tag-class>
+    <body-content>JSP</body-content>
+    <description>
+        Supplies an argument for parametric replacement to a containing
+        <message> tag
+    </description>
+    <attribute>
+        <name>value</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>formatNumber</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.fmt.FormatNumberTag</tag-class>
+    <body-content>JSP</body-content>
+    <description>
+        Formats a numeric value as a number, currency, or percentage
+    </description>
+    <attribute>
+        <name>value</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>type</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>pattern</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>currencyCode</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>currencySymbol</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>groupingUsed</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>maxIntegerDigits</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>minIntegerDigits</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>maxFractionDigits</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>minFractionDigits</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>parseNumber</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.fmt.ParseNumberTag</tag-class>
+    <body-content>JSP</body-content>
+    <description>
+        Parses the string representation of a number, currency, or percentage
+    </description>
+    <attribute>
+        <name>value</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>type</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>pattern</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>parseLocale</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>integerOnly</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>formatDate</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.fmt.FormatDateTag</tag-class>
+    <body-content>empty</body-content>
+    <description>
+        Formats a date and/or time using the supplied styles and pattern
+    </description>
+    <attribute>
+        <name>value</name>
+        <required>true</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>type</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>dateStyle</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>timeStyle</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>pattern</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>timeZone</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>parseDate</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.fmt.ParseDateTag</tag-class>
+    <body-content>JSP</body-content>
+    <description>
+        Parses the string representation of a date and/or time
+    </description>
+    <attribute>
+        <name>value</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>type</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>dateStyle</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>timeStyle</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>pattern</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>timeZone</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>parseLocale</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+</taglib>
diff --git a/standard/conf/fmt-1_0.tld b/standard/conf/fmt-1_0.tld
new file mode 100644
index 0000000..20523ee
--- /dev/null
+++ b/standard/conf/fmt-1_0.tld
@@ -0,0 +1,442 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE taglib
+  PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
+  "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
+<taglib>
+  <tlib-version>1.0</tlib-version>
+  <jsp-version>1.2</jsp-version>
+  <short-name>fmt</short-name>
+  <uri>http://java.sun.com/jstl/fmt</uri>
+  <display-name>JSTL fmt</display-name>
+  <description>JSTL 1.0 i18n-capable formatting library</description>
+
+  <validator>
+    <validator-class>
+	org.apache.taglibs.standard.tlv.JstlFmtTLV
+    </validator-class>
+    <init-param>
+	<param-name>expressionAttributes</param-name>
+	<param-value>
+            requestEncoding:value 
+	    setLocale:value
+	    setLocale:variant
+	    timeZone:value
+	    setTimeZone:value
+	    bundle:basename
+	    bundle:prefix
+            setBundle:basename
+	    message:key
+	    message:bundle
+	    param:value
+	    formatNumber:value
+	    formatNumber:pattern
+            formatNumber:currencyCode
+            formatNumber:currencySymbol
+            formatNumber:groupingUsed
+            formatNumber:maxIntegerDigits
+            formatNumber:minIntegerDigits
+            formatNumber:maxFractionDigits
+            formatNumber:minFractionDigits
+	    parseNumber:value
+	    parseNumber:pattern
+	    parseNumber:parseLocale
+            parseNumber:integerOnly
+	    formatDate:value
+	    formatDate:pattern
+	    formatDate:timeZone
+	    parseDate:value
+	    parseDate:pattern
+	    parseDate:timeZone
+	    parseDate:parseLocale
+	</param-value>
+	<description>
+	    Whitespace-separated list of colon-separated token pairs
+	    describing tag:attribute combinations that accept expressions.
+	    The validator uses this information to determine which
+	    attributes need their syntax validated.
+	</description>
+     </init-param>
+  </validator>
+
+  <tag>
+    <name>requestEncoding</name>
+    <tag-class>org.apache.taglibs.standard.tag.el.fmt.RequestEncodingTag</tag-class>
+    <body-content>empty</body-content>
+    <description>
+        Sets the request character encoding
+    </description>
+    <attribute>
+        <name>value</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>setLocale</name>
+    <tag-class>org.apache.taglibs.standard.tag.el.fmt.SetLocaleTag</tag-class>
+    <body-content>empty</body-content>
+    <description>
+        Stores the given locale in the locale configuration variable
+    </description>
+    <attribute>
+        <name>value</name>
+        <required>true</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>variant</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>timeZone</name>
+    <tag-class>org.apache.taglibs.standard.tag.el.fmt.TimeZoneTag</tag-class>
+    <body-content>JSP</body-content>
+    <description>
+        Specifies the time zone for any time formatting or parsing actions
+        nested in its body
+    </description>
+    <attribute>
+        <name>value</name>
+        <required>true</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>setTimeZone</name>
+    <tag-class>org.apache.taglibs.standard.tag.el.fmt.SetTimeZoneTag</tag-class>
+    <body-content>empty</body-content>
+    <description>
+        Stores the given time zone in the time zone configuration variable
+    </description>
+    <attribute>
+        <name>value</name>
+        <required>true</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>bundle</name>
+    <tag-class>org.apache.taglibs.standard.tag.el.fmt.BundleTag</tag-class>
+    <body-content>JSP</body-content>
+    <description>
+        Loads a resource bundle to be used by its tag body
+    </description>
+    <attribute>
+        <name>basename</name>
+        <required>true</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>prefix</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>setBundle</name>
+    <tag-class>org.apache.taglibs.standard.tag.el.fmt.SetBundleTag</tag-class>
+    <body-content>empty</body-content>
+    <description>
+        Loads a resource bundle and stores it in the named scoped variable or
+        the bundle configuration variable
+    </description>
+    <attribute>
+        <name>basename</name>
+        <required>true</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>message</name>
+    <tag-class>org.apache.taglibs.standard.tag.el.fmt.MessageTag</tag-class>
+    <body-content>JSP</body-content>
+    <description>
+        Maps key to localized message and performs parametric replacement
+    </description>
+    <attribute>
+        <name>key</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>bundle</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>param</name>
+    <tag-class>org.apache.taglibs.standard.tag.el.fmt.ParamTag</tag-class>
+    <body-content>JSP</body-content>
+    <description>
+        Supplies an argument for parametric replacement to a containing
+        <message> tag
+    </description>
+    <attribute>
+        <name>value</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>formatNumber</name>
+    <tag-class>org.apache.taglibs.standard.tag.el.fmt.FormatNumberTag</tag-class>
+    <body-content>JSP</body-content>
+    <description>
+        Formats a numeric value as a number, currency, or percentage
+    </description>
+    <attribute>
+        <name>value</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>type</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>pattern</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>currencyCode</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>currencySymbol</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>groupingUsed</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>maxIntegerDigits</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>minIntegerDigits</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>maxFractionDigits</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>minFractionDigits</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>parseNumber</name>
+    <tag-class>org.apache.taglibs.standard.tag.el.fmt.ParseNumberTag</tag-class>
+    <body-content>JSP</body-content>
+    <description>
+        Parses the string representation of a number, currency, or percentage
+    </description>
+    <attribute>
+        <name>value</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>type</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>pattern</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>parseLocale</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>integerOnly</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>formatDate</name>
+    <tag-class>org.apache.taglibs.standard.tag.el.fmt.FormatDateTag</tag-class>
+    <body-content>empty</body-content>
+    <description>
+        Formats a date and/or time using the supplied styles and pattern
+    </description>
+    <attribute>
+        <name>value</name>
+        <required>true</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>type</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>dateStyle</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>timeStyle</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>pattern</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>timeZone</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>parseDate</name>
+    <tag-class>org.apache.taglibs.standard.tag.el.fmt.ParseDateTag</tag-class>
+    <body-content>JSP</body-content>
+    <description>
+        Parses the string representation of a date and/or time
+    </description>
+    <attribute>
+        <name>value</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>type</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>dateStyle</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>timeStyle</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>pattern</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>timeZone</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>parseLocale</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+</taglib>
diff --git a/standard/conf/fmt.tld b/standard/conf/fmt.tld
new file mode 100644
index 0000000..3b9a54a
--- /dev/null
+++ b/standard/conf/fmt.tld
@@ -0,0 +1,671 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
+    version="2.0">
+    
+  <description>JSTL 1.1 i18n-capable formatting library</description>
+  <display-name>JSTL fmt</display-name>
+  <tlib-version>1.1</tlib-version>
+  <short-name>fmt</short-name>
+  <uri>http://java.sun.com/jsp/jstl/fmt</uri>
+
+  <validator>
+    <description>
+        Provides core validation features for JSTL tags.
+    </description>
+    <validator-class>
+        org.apache.taglibs.standard.tlv.JstlFmtTLV
+    </validator-class>
+  </validator>
+
+  <tag>
+    <description>
+        Sets the request character encoding
+    </description>
+    <name>requestEncoding</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.fmt.RequestEncodingTag</tag-class>
+    <body-content>empty</body-content>
+    <attribute>
+        <description>
+Name of character encoding to be applied when
+decoding request parameters.
+        </description>
+        <name>value</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+        Stores the given locale in the locale configuration variable
+    </description>
+    <name>setLocale</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.fmt.SetLocaleTag</tag-class>
+    <body-content>empty</body-content>
+    <attribute>
+        <description>
+A String value is interpreted as the
+printable representation of a locale, which
+must contain a two-letter (lower-case)
+language code (as defined by ISO-639),
+and may contain a two-letter (upper-case)
+country code (as defined by ISO-3166).
+Language and country codes must be
+separated by hyphen (-) or underscore
+(_).        
+	</description>
+        <name>value</name>
+        <required>true</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Vendor- or browser-specific variant.
+See the java.util.Locale javadocs for
+more information on variants.
+        </description>
+        <name>variant</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Scope of the locale configuration variable.
+        </description>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+        Specifies the time zone for any time formatting or parsing actions
+        nested in its body
+    </description>
+    <name>timeZone</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.fmt.TimeZoneTag</tag-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <description>
+The time zone. A String value is interpreted as
+a time zone ID. This may be one of the time zone
+IDs supported by the Java platform (such as
+"America/Los_Angeles") or a custom time zone
+ID (such as "GMT-8"). See
+java.util.TimeZone for more information on
+supported time zone formats.
+        </description>
+        <name>value</name>
+        <required>true</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+        Stores the given time zone in the time zone configuration variable
+    </description>
+    <name>setTimeZone</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.fmt.SetTimeZoneTag</tag-class>
+    <body-content>empty</body-content>
+    <attribute>
+        <description>
+The time zone. A String value is interpreted as
+a time zone ID. This may be one of the time zone
+IDs supported by the Java platform (such as
+"America/Los_Angeles") or a custom time zone
+ID (such as "GMT-8"). See java.util.TimeZone for
+more information on supported time zone
+formats.
+        </description>
+        <name>value</name>
+        <required>true</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Name of the exported scoped variable which
+stores the time zone of type
+java.util.TimeZone.
+        </description>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Scope of var or the time zone configuration
+variable.
+        </description>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+        Loads a resource bundle to be used by its tag body
+    </description>
+    <name>bundle</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.fmt.BundleTag</tag-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <description>
+Resource bundle base name. This is the bundle's
+fully-qualified resource name, which has the same
+form as a fully-qualified class name, that is, it uses
+"." as the package component separator and does not
+have any file type (such as ".class" or ".properties")
+suffix.
+        </description>
+        <name>basename</name>
+        <required>true</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Prefix to be prepended to the value of the message
+key of any nested <fmt:message> action.
+        </description>
+        <name>prefix</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+        Loads a resource bundle and stores it in the named scoped variable or
+        the bundle configuration variable
+    </description>
+    <name>setBundle</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.fmt.SetBundleTag</tag-class>
+    <body-content>empty</body-content>
+    <attribute>
+        <description>
+Resource bundle base name. This is the bundle's
+fully-qualified resource name, which has the same
+form as a fully-qualified class name, that is, it uses
+"." as the package component separator and does not
+have any file type (such as ".class" or ".properties")
+suffix.
+        </description>
+        <name>basename</name>
+        <required>true</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Name of the exported scoped variable which stores
+the i18n localization context of type
+javax.servlet.jsp.jstl.fmt.LocalizationC
+ontext.
+        </description>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Scope of var or the localization context
+configuration variable.
+        </description>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+        Maps key to localized message and performs parametric replacement
+    </description>
+    <name>message</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.fmt.MessageTag</tag-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <description>
+Message key to be looked up.
+        </description>
+        <name>key</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Localization context in whose resource
+bundle the message key is looked up.
+        </description>
+        <name>bundle</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Name of the exported scoped variable
+which stores the localized message.
+        </description>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Scope of var.
+        </description>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+        Supplies an argument for parametric replacement to a containing
+        <message> tag
+    </description>
+    <name>param</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.fmt.ParamTag</tag-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <description>
+Argument used for parametric replacement.
+        </description>
+        <name>value</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+        Formats a numeric value as a number, currency, or percentage
+    </description>
+    <name>formatNumber</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.fmt.FormatNumberTag</tag-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <description>
+Numeric value to be formatted.
+        </description>
+        <name>value</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Specifies whether the value is to be
+formatted as number, currency, or
+percentage.
+        </description>
+        <name>type</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Custom formatting pattern.
+        </description>
+        <name>pattern</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+ISO 4217 currency code. Applied only
+when formatting currencies (i.e. if type is
+equal to "currency"); ignored otherwise.
+        </description>
+        <name>currencyCode</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Currency symbol. Applied only when
+formatting currencies (i.e. if type is equal
+to "currency"); ignored otherwise.
+        </description>
+        <name>currencySymbol</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Specifies whether the formatted output
+will contain any grouping separators.
+        </description>
+        <name>groupingUsed</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Maximum number of digits in the integer
+portion of the formatted output.
+        </description>
+        <name>maxIntegerDigits</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Minimum number of digits in the integer
+portion of the formatted output.
+        </description>
+        <name>minIntegerDigits</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Maximum number of digits in the
+fractional portion of the formatted output.
+        </description>
+        <name>maxFractionDigits</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Minimum number of digits in the
+fractional portion of the formatted output.
+        </description>
+        <name>minFractionDigits</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Name of the exported scoped variable
+which stores the formatted result as a
+String.
+        </description>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Scope of var.
+        </description>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+        Parses the string representation of a number, currency, or percentage
+    </description>
+    <name>parseNumber</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.fmt.ParseNumberTag</tag-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <description>
+String to be parsed.
+        </description>
+        <name>value</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Specifies whether the string in the value
+attribute should be parsed as a number,
+currency, or percentage.
+        </description>
+        <name>type</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Custom formatting pattern that determines
+how the string in the value attribute is to be
+parsed.
+        </description>
+        <name>pattern</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Locale whose default formatting pattern (for
+numbers, currencies, or percentages,
+respectively) is to be used during the parse
+operation, or to which the pattern specified
+via the pattern attribute (if present) is
+applied.
+        </description>
+        <name>parseLocale</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Specifies whether just the integer portion of
+the given value should be parsed.
+        </description>
+        <name>integerOnly</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Name of the exported scoped variable which
+stores the parsed result (of type
+java.lang.Number).
+        </description>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Scope of var.
+        </description>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+        Formats a date and/or time using the supplied styles and pattern
+    </description>
+    <name>formatDate</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.fmt.FormatDateTag</tag-class>
+    <body-content>empty</body-content>
+    <attribute>
+        <description>
+Date and/or time to be formatted.
+        </description>
+        <name>value</name>
+        <required>true</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Specifies whether the time, the date, or both
+the time and date components of the given
+date are to be formatted. 
+        </description>
+        <name>type</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Predefined formatting style for dates. Follows
+the semantics defined in class
+java.text.DateFormat. Applied only
+when formatting a date or both a date and
+time (i.e. if type is missing or is equal to
+"date" or "both"); ignored otherwise.
+        </description>
+        <name>dateStyle</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Predefined formatting style for times. Follows
+the semantics defined in class
+java.text.DateFormat. Applied only
+when formatting a time or both a date and
+time (i.e. if type is equal to "time" or "both");
+ignored otherwise.
+        </description>
+        <name>timeStyle</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Custom formatting style for dates and times.
+        </description>
+        <name>pattern</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Time zone in which to represent the formatted
+time.
+        </description>
+        <name>timeZone</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Name of the exported scoped variable which
+stores the formatted result as a String.
+        </description>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Scope of var.
+        </description>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+        Parses the string representation of a date and/or time
+    </description>
+    <name>parseDate</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.fmt.ParseDateTag</tag-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <description>
+Date string to be parsed.
+        </description>
+        <name>value</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Specifies whether the date string in the
+value attribute is supposed to contain a
+time, a date, or both.
+        </description>
+        <name>type</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Predefined formatting style for days
+which determines how the date
+component of the date string is to be
+parsed. Applied only when formatting a
+date or both a date and time (i.e. if type
+is missing or is equal to "date" or "both");
+ignored otherwise.
+        </description>
+        <name>dateStyle</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Predefined formatting styles for times
+which determines how the time
+component in the date string is to be
+parsed. Applied only when formatting a
+time or both a date and time (i.e. if type
+is equal to "time" or "both"); ignored
+otherwise.
+        </description>
+        <name>timeStyle</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Custom formatting pattern which
+determines how the date string is to be
+parsed.
+        </description>
+        <name>pattern</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Time zone in which to interpret any time
+information in the date string.
+        </description>
+        <name>timeZone</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Locale whose predefined formatting styles
+for dates and times are to be used during
+the parse operation, or to which the
+pattern specified via the pattern
+attribute (if present) is applied.
+        </description>
+        <name>parseLocale</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Name of the exported scoped variable in
+which the parsing result (of type
+java.util.Date) is stored.
+        </description>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Scope of var.
+        </description>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+</taglib>
diff --git a/standard/conf/fn.tld b/standard/conf/fn.tld
new file mode 100644
index 0000000..12d4ca8
--- /dev/null
+++ b/standard/conf/fn.tld
@@ -0,0 +1,207 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
+  version="2.0">
+    
+  <description>JSTL 1.1 functions library</description>
+  <display-name>JSTL functions</display-name>
+  <tlib-version>1.1</tlib-version>
+  <short-name>fn</short-name>
+  <uri>http://java.sun.com/jsp/jstl/functions</uri>
+
+  <function>
+    <description>
+      Tests if an input string contains the specified substring.
+    </description>
+    <name>contains</name>
+    <function-class>org.apache.taglibs.standard.functions.Functions</function-class>
+    <function-signature>boolean contains(java.lang.String, java.lang.String)</function-signature>
+    <example>
+      <c:if test="${fn:contains(name, searchString)}">
+    </example>
+  </function>
+
+  <function>
+    <description>
+      Tests if an input string contains the specified substring in a case insensitive way.
+    </description>
+    <name>containsIgnoreCase</name>
+    <function-class>org.apache.taglibs.standard.functions.Functions</function-class>
+    <function-signature>boolean containsIgnoreCase(java.lang.String, java.lang.String)</function-signature>
+    <example>
+      <c:if test="${fn:containsIgnoreCase(name, searchString)}">
+    </example>
+  </function>
+
+  <function>
+    <description>
+      Tests if an input string ends with the specified suffix.
+    </description>
+    <name>endsWith</name>
+    <function-class>org.apache.taglibs.standard.functions.Functions</function-class>
+    <function-signature>boolean endsWith(java.lang.String, java.lang.String)</function-signature>
+    <example>
+      <c:if test="${fn:endsWith(filename, ".txt")}">
+    </example>
+  </function>
+
+  <function>
+    <description>
+      Escapes characters that could be interpreted as XML markup.
+    </description>
+    <name>escapeXml</name>
+    <function-class>org.apache.taglibs.standard.functions.Functions</function-class>
+    <function-signature>java.lang.String escapeXml(java.lang.String)</function-signature>
+    <example>
+      ${fn:escapeXml(param:info)}
+    </example>
+  </function>
+
+  <function>
+    <description>
+      Returns the index withing a string of the first occurrence of a specified substring.
+    </description>
+    <name>indexOf</name>
+    <function-class>org.apache.taglibs.standard.functions.Functions</function-class>
+    <function-signature>int indexOf(java.lang.String, java.lang.String)</function-signature>
+    <example>
+      ${fn:indexOf(name, "-")}
+    </example>
+  </function>
+
+  <function>
+    <description>
+      Joins all elements of an array into a string.
+    </description>
+    <name>join</name>
+    <function-class>org.apache.taglibs.standard.functions.Functions</function-class>
+    <function-signature>java.lang.String join(java.lang.String[], java.lang.String)</function-signature>
+    <example>
+      ${fn:join(array, ";")}
+    </example>
+  </function>
+
+  <function>
+    <description>
+      Returns the number of items in a collection, or the number of characters in a string.
+    </description>
+    <name>length</name>
+    <function-class>org.apache.taglibs.standard.functions.Functions</function-class>
+    <function-signature>int length(java.lang.Object)</function-signature>
+    <example>
+      You have ${fn:length(shoppingCart.products)} in your shopping cart.
+    </example>
+  </function>
+
+  <function>
+    <description>
+      Returns a string resulting from replacing in an input string all occurrences
+      of a "before" string into an "after" substring.
+    </description>
+    <name>replace</name>
+    <function-class>org.apache.taglibs.standard.functions.Functions</function-class>
+    <function-signature>java.lang.String replace(java.lang.String, java.lang.String, java.lang.String)</function-signature>
+    <example>
+      ${fn:replace(text, "-", "•")}
+    </example>
+  </function>
+
+  <function>
+    <description>
+      Splits a string into an array of substrings.
+    </description>
+    <name>split</name>
+    <function-class>org.apache.taglibs.standard.functions.Functions</function-class>
+    <function-signature>java.lang.String[] split(java.lang.String, java.lang.String)</function-signature>
+    <example>
+      ${fn:split(customerNames, ";")}
+    </example>
+  </function>
+
+  <function>
+    <description>
+      Tests if an input string starts with the specified prefix.
+    </description>
+    <name>startsWith</name>
+    <function-class>org.apache.taglibs.standard.functions.Functions</function-class>
+    <function-signature>boolean startsWith(java.lang.String, java.lang.String)</function-signature>
+    <example>
+      <c:if test="${fn:startsWith(product.id, "100-")}">
+    </example>
+  </function>
+
+  <function>
+    <description>
+      Returns a subset of a string.
+    </description>
+    <name>substring</name>
+    <function-class>org.apache.taglibs.standard.functions.Functions</function-class>
+    <function-signature>java.lang.String substring(java.lang.String, int, int)</function-signature>
+    <example>
+      P.O. Box: ${fn:substring(zip, 6, -1)}
+    </example>
+  </function>
+
+  <function>
+    <description>
+      Returns a subset of a string following a specific substring.
+    </description>
+    <name>substringAfter</name>
+    <function-class>org.apache.taglibs.standard.functions.Functions</function-class>
+    <function-signature>java.lang.String substringAfter(java.lang.String, java.lang.String)</function-signature>
+    <example>
+      P.O. Box: ${fn:substringAfter(zip, "-")}
+    </example>
+  </function>
+
+  <function>
+    <description>
+      Returns a subset of a string before a specific substring.
+    </description>
+    <name>substringBefore</name>
+    <function-class>org.apache.taglibs.standard.functions.Functions</function-class>
+    <function-signature>java.lang.String substringBefore(java.lang.String, java.lang.String)</function-signature>
+    <example>
+      Zip (without P.O. Box): ${fn:substringBefore(zip, "-")}
+    </example>
+  </function>
+
+  <function>
+    <description>
+      Converts all of the characters of a string to lower case.
+    </description>
+    <name>toLowerCase</name>
+    <function-class>org.apache.taglibs.standard.functions.Functions</function-class>
+    <function-signature>java.lang.String toLowerCase(java.lang.String)</function-signature>
+    <example>
+      Product name: ${fn.toLowerCase(product.name)}
+    </example>
+  </function>
+
+  <function>
+    <description>
+      Converts all of the characters of a string to upper case.
+    </description>
+    <name>toUpperCase</name>
+    <function-class>org.apache.taglibs.standard.functions.Functions</function-class>
+    <function-signature>java.lang.String toUpperCase(java.lang.String)</function-signature>
+    <example>
+      Product name: ${fn.UpperCase(product.name)}
+    </example>
+  </function>
+
+  <function>
+    <description>
+      Removes white spaces from both ends of a string.
+    </description>
+    <name>trim</name>
+    <function-class>org.apache.taglibs.standard.functions.Functions</function-class>
+    <function-signature>java.lang.String trim(java.lang.String)</function-signature>
+    <example>
+      Name: ${fn.trim(name)}
+    </example>  
+  </function>
+
+</taglib>
diff --git a/standard/conf/permittedTaglibs.tld b/standard/conf/permittedTaglibs.tld
new file mode 100644
index 0000000..8c0c404
--- /dev/null
+++ b/standard/conf/permittedTaglibs.tld
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
+    version="2.0">
+  <description>
+    Restricts JSP pages to the JSTL tag libraries
+  </description>    
+  <display-name>permittedTaglibs</display-name>
+  <tlib-version>1.1</tlib-version>
+  <short-name>permittedTaglibs</short-name>
+  <uri>http://jakarta.apache.org/taglibs/standard/permittedTaglibs</uri>
+
+  <validator>
+    <validator-class>
+	javax.servlet.jsp.jstl.tlv.PermittedTaglibsTLV
+    </validator-class>        
+    <init-param>
+      <description>
+        Whitespace-separated list of taglib URIs to permit.  This example
+	TLD for the Standard Taglib allows only JSTL 'el' taglibs to be
+	imported.
+      </description>        
+      <param-name>permittedTaglibs</param-name>
+      <param-value>
+	http://java.sun.com/jsp/jstl/core
+	http://java.sun.com/jsp/jstl/fmt
+	http://java.sun.com/jsp/jstl/sql
+	http://java.sun.com/jsp/jstl/xml
+      </param-value>
+    </init-param>
+  </validator>
+</taglib>
diff --git a/standard/conf/scriptfree.tld b/standard/conf/scriptfree.tld
new file mode 100644
index 0000000..62ceb43
--- /dev/null
+++ b/standard/conf/scriptfree.tld
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
+    version="2.0">
+  <description>
+    Validates JSP pages to prohibit use of scripting elements.
+  </description>
+  <tlib-version>1.1</tlib-version>
+  <short-name>scriptfree</short-name>
+  <uri>http://jakarta.apache.org/taglibs/standard/scriptfree</uri>
+
+  <validator>
+    <description>
+      Validates prohibitions against scripting elements.
+    </description>
+    <validator-class>
+    javax.servlet.jsp.jstl.tlv.ScriptFreeTLV
+    </validator-class>
+    <init-param>
+      <description>
+        Controls whether or not declarations are considered valid.
+      </description>
+      <param-name>allowDeclarations</param-name>
+      <param-value>false</param-value>
+    </init-param>
+    <init-param>
+      <description>
+        Controls whether or not scriptlets are considered valid.
+      </description>
+      <param-name>allowScriptlets</param-name>
+      <param-value>false</param-value>
+    </init-param>
+    <init-param>
+      <description>
+        Controls whether or not top-level expressions are considered valid.
+      </description>
+      <param-name>allowExpressions</param-name>
+      <param-value>false</param-value>
+    </init-param>
+    <init-param>
+      <description>
+        Controls whether or not expressions used to supply request-time
+        attribute values are considered valid.
+      </description>
+      <param-name>allowRTExpressions</param-name>
+      <param-value>false</param-value>
+    </init-param>
+  </validator>
+</taglib>
diff --git a/standard/conf/sql-1_0-rt.tld b/standard/conf/sql-1_0-rt.tld
new file mode 100644
index 0000000..c2fe525
--- /dev/null
+++ b/standard/conf/sql-1_0-rt.tld
@@ -0,0 +1,188 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE taglib
+  PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
+  "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
+<taglib>
+  <tlib-version>1.0</tlib-version>
+  <jsp-version>1.2</jsp-version>
+  <short-name>sql_rt</short-name>
+  <uri>http://java.sun.com/jstl/sql_rt</uri>
+  <display-name>JSTL sql RT</display-name>
+  <description>JSTL 1.0 sql library</description>
+
+  <validator>
+    <validator-class>
+        org.apache.taglibs.standard.tlv.JstlSqlTLV
+    </validator-class>
+    <description>
+        Provides core validation features for JSTL tags.
+    </description>
+  </validator>
+
+  <tag>
+    <name>transaction</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.sql.TransactionTag</tag-class>
+    <body-content>JSP</body-content>
+    <description>
+        Provides nested database action elements with a shared Connection,
+        set up to execute all statements as one transaction.
+    </description>
+    <attribute>
+        <name>dataSource</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>isolation</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>query</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.sql.QueryTag</tag-class>
+    <body-content>JSP</body-content>
+    <description>
+        Executes the SQL query defined in its body or through the
+        sql attribute.
+    </description>
+    <attribute>
+        <name>var</name>
+        <required>true</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>sql</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>dataSource</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>startRow</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>maxRows</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>update</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.sql.UpdateTag</tag-class>
+    <body-content>JSP</body-content>
+    <description>
+        Executes the SQL update defined in its body or through the
+        sql attribute.
+    </description>
+    <attribute>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>sql</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>dataSource</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>param</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.sql.ParamTag</tag-class>
+    <body-content>JSP</body-content>
+    <description>
+        Sets a parameter in an SQL statement to the specified value.
+    </description>
+    <attribute>
+        <name>value</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>dateParam</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.sql.DateParamTag</tag-class>
+    <body-content>empty</body-content>
+    <description>
+        Sets a parameter in an SQL statement to the specified java.util.Date value.
+    </description>
+    <attribute>
+        <name>value</name>
+        <required>true</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>type</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>setDataSource</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.sql.SetDataSourceTag</tag-class>
+    <body-content>empty</body-content>
+    <description>
+        Creates a simple DataSource suitable only for prototyping.
+    </description>
+    <attribute>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>dataSource</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>driver</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>url</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>user</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>password</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+  </tag>
+</taglib>
diff --git a/standard/conf/sql-1_0.tld b/standard/conf/sql-1_0.tld
new file mode 100644
index 0000000..2f8a328
--- /dev/null
+++ b/standard/conf/sql-1_0.tld
@@ -0,0 +1,213 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE taglib
+  PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
+  "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
+<taglib>
+  <tlib-version>1.0</tlib-version>
+  <jsp-version>1.2</jsp-version>
+  <short-name>sql</short-name>
+  <uri>http://java.sun.com/jstl/sql</uri>
+  <display-name>JSTL sql</display-name>
+  <description>JSTL 1.0 sql library</description>
+
+  <validator>
+    <validator-class>
+	org.apache.taglibs.standard.tlv.JstlSqlTLV
+    </validator-class>
+    <init-param>
+        <param-name>expressionAttributes</param-name>
+        <param-value>
+        transaction:dataSource
+        transaction:isolation
+        query:sql
+        query:dataSource
+        query:startRow
+        query:maxRows
+        update:sql
+        update:dataSource
+        param:value
+        dateParam:value
+        dateParam:type
+        setDataSource:dataSource
+        setDataSource:driver
+        setDataSource:url
+        setDataSource:user
+        setDataSource:password
+        </param-value>
+        <description>
+            Whitespace-separated list of colon-separated token pairs
+            describing tag:attribute combinations that accept expressions.
+            The validator uses this information to determine which
+            attributes need their syntax validated.
+        </description>
+     </init-param>
+  </validator>
+
+  <tag>
+    <name>transaction</name>
+    <tag-class>org.apache.taglibs.standard.tag.el.sql.TransactionTag</tag-class>
+    <body-content>JSP</body-content>
+    <description>
+        Provides nested database action elements with a shared Connection,
+        set up to execute all statements as one transaction.
+    </description>
+    <attribute>
+        <name>dataSource</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>isolation</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>query</name>
+    <tag-class>org.apache.taglibs.standard.tag.el.sql.QueryTag</tag-class>
+    <body-content>JSP</body-content>
+    <description>
+        Executes the SQL query defined in its body or through the
+        sql attribute.
+    </description>
+    <attribute>
+        <name>var</name>
+        <required>true</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>sql</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>dataSource</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>startRow</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>maxRows</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>update</name>
+    <tag-class>org.apache.taglibs.standard.tag.el.sql.UpdateTag</tag-class>
+    <body-content>JSP</body-content>
+    <description>
+        Executes the SQL update defined in its body or through the
+        sql attribute.
+    </description>
+    <attribute>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>sql</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>dataSource</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>param</name>
+    <tag-class>org.apache.taglibs.standard.tag.el.sql.ParamTag</tag-class>
+    <body-content>JSP</body-content>
+    <description>
+        Sets a parameter in an SQL statement to the specified value.
+    </description>
+    <attribute>
+        <name>value</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>dateParam</name>
+    <tag-class>org.apache.taglibs.standard.tag.el.sql.DateParamTag</tag-class>
+    <body-content>empty</body-content>
+    <description>
+        Sets a parameter in an SQL statement to the specified java.util.Date val
+ue.
+    </description>
+    <attribute>
+        <name>value</name>
+        <required>true</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>type</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>setDataSource</name>
+    <tag-class>org.apache.taglibs.standard.tag.el.sql.SetDataSourceTag</tag-class>
+    <body-content>empty</body-content>
+    <description>
+        Creates a simple DataSource suitable only for prototyping.
+    </description>
+    <attribute>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>dataSource</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>driver</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>url</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>user</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>password</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+</taglib>
diff --git a/standard/conf/sql.tld b/standard/conf/sql.tld
new file mode 100644
index 0000000..e53445b
--- /dev/null
+++ b/standard/conf/sql.tld
@@ -0,0 +1,289 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
+    version="2.0">
+    
+  <description>JSTL 1.1 sql library</description>
+  <display-name>JSTL sql</display-name>
+  <tlib-version>1.1</tlib-version>
+  <short-name>sql</short-name>
+  <uri>http://java.sun.com/jsp/jstl/sql</uri>
+
+  <validator>
+    <description>
+        Provides core validation features for JSTL tags.
+    </description>
+    <validator-class>
+        org.apache.taglibs.standard.tlv.JstlSqlTLV
+    </validator-class>
+  </validator>
+
+  <tag>
+    <description>
+        Provides nested database action elements with a shared Connection,
+        set up to execute all statements as one transaction.
+    </description>
+    <name>transaction</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.sql.TransactionTag</tag-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <description>
+DataSource associated with the database to access. A
+String value represents a relative path to a JNDI
+resource or the parameters for the JDBC
+DriverManager facility.
+        </description>
+        <name>dataSource</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Transaction isolation level. If not specified, it is the
+isolation level the DataSource has been configured
+with.
+        </description>
+        <name>isolation</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+        Executes the SQL query defined in its body or through the
+        sql attribute.
+    </description>
+    <name>query</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.sql.QueryTag</tag-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <description>
+Name of the exported scoped variable for the
+query result. The type of the scoped variable is
+javax.servlet.jsp.jstl.sql.
+Result (see Chapter 16 "Java APIs").
+        </description>
+        <name>var</name>
+        <required>true</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Scope of var.
+        </description>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+SQL query statement.
+        </description>
+        <name>sql</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Data source associated with the database to
+query. A String value represents a relative path
+to a JNDI resource or the parameters for the
+DriverManager class.
+        </description>
+        <name>dataSource</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+The returned Result object includes the rows
+starting at the specified index. The first row of
+the original query result set is at index 0. If not
+specified, rows are included starting from the
+first row at index 0.
+        </description>
+        <name>startRow</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+The maximum number of rows to be included in
+the query result. If not specified, or set to -1, no
+limit on the maximum number of rows is
+enforced.
+        </description>
+        <name>maxRows</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+        Executes the SQL update defined in its body or through the
+        sql attribute.
+    </description>
+    <name>update</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.sql.UpdateTag</tag-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <description>
+Name of the exported scoped variable for the result
+of the database update. The type of the scoped
+variable is java.lang.Integer.
+        </description>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Scope of var.
+        </description>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+SQL update statement.
+        </description>
+        <name>sql</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Data source associated with the database to update.
+A String value represents a relative path to a JNDI
+resource or the parameters for the JDBC
+DriverManager class.
+        </description>
+        <name>dataSource</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+        Sets a parameter in an SQL statement to the specified value.
+    </description>
+    <name>param</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.sql.ParamTag</tag-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <description>
+Parameter value.
+        </description>
+        <name>value</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+        Sets a parameter in an SQL statement to the specified java.util.Date value.
+    </description>
+    <name>dateParam</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.sql.DateParamTag</tag-class>
+    <body-content>empty</body-content>
+    <attribute>
+        <description>
+Parameter value for DATE, TIME, or
+TIMESTAMP column in a database table.
+        </description>
+        <name>value</name>
+        <required>true</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+One of "date", "time" or "timestamp".
+        </description>
+        <name>type</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+        Creates a simple DataSource suitable only for prototyping.
+    </description>
+    <name>setDataSource</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.sql.SetDataSourceTag</tag-class>
+    <body-content>empty</body-content>
+    <attribute>
+        <description>
+Name of the exported scoped variable
+for the data source specified. Type can
+be String or DataSource.
+        </description>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+If var is specified, scope of the
+exported variable. Otherwise, scope of
+the data source configuration variable.
+        </description>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Data source. If specified as a string, it
+can either be a relative path to a JNDI
+resource, or a JDBC parameters string
+as defined in Section 10.1.1.
+        </description>
+        <name>dataSource</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+JDBC parameter: driver class name.
+        </description>
+        <name>driver</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+JDBC parameter: URL associated with
+the database.
+        </description>
+        <name>url</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+JDBC parameter: database user on
+whose behalf the connection to the
+database is being made.
+        </description>
+        <name>user</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+JDBC parameter: user password
+        </description>
+        <name>password</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+  </tag>
+</taglib>
diff --git a/standard/conf/x-1_0-rt.tld b/standard/conf/x-1_0-rt.tld
new file mode 100644
index 0000000..e7062b7
--- /dev/null
+++ b/standard/conf/x-1_0-rt.tld
@@ -0,0 +1,256 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE taglib
+  PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
+  "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
+<taglib>
+  <tlib-version>1.0</tlib-version>
+  <jsp-version>1.2</jsp-version>
+  <short-name>x_rt</short-name>
+  <uri>http://java.sun.com/jstl/xml_rt</uri>
+  <display-name>JSTL XML RT</display-name>
+  <description>JSTL 1.0 XML library</description>
+
+  <validator>
+    <validator-class>
+	org.apache.taglibs.standard.tlv.JstlXmlTLV
+    </validator-class>
+    <description>
+        Provides validation features for JSTL XML tags.
+    </description>
+  </validator>
+
+  <tag>
+    <name>choose</name>
+    <tag-class>org.apache.taglibs.standard.tag.common.core.ChooseTag</tag-class>
+    <body-content>JSP</body-content>
+    <description>
+        Simple conditional tag that establishes a context for
+        mutually exclusive conditional operations, marked by
+        <when> and <otherwise>
+    </description>
+  </tag>
+
+  <tag>
+    <name>out</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.xml.ExprTag</tag-class>
+    <body-content>empty</body-content>
+    <description>
+	Like <%= ... >, but for XPath expressions.
+    </description>
+    <attribute>
+        <name>select</name>
+        <required>true</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>escapeXml</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>if</name>
+    <tag-class>org.apache.taglibs.standard.tag.common.xml.IfTag</tag-class>
+    <body-content>JSP</body-content>
+    <description>
+        XML conditional tag, which evalutes its body if the
+        supplied XPath expression evalutes to 'true' as a boolean
+    </description>
+    <attribute>
+        <name>select</name>
+        <required>true</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>forEach</name>
+    <tag-class>org.apache.taglibs.standard.tag.common.xml.ForEachTag</tag-class>
+    <body-content>JSP</body-content>
+    <description>
+	XML iteration tag.
+    </description>
+    <attribute>
+	<name>var</name>
+	<required>false</required>
+	<rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+	<name>select</name>
+	<required>true</required>
+	<rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>otherwise</name>
+    <tag-class>org.apache.taglibs.standard.tag.common.core.OtherwiseTag</tag-class>
+    <body-content>JSP</body-content>
+    <description>
+	Subtag of <choose> that follows <when> tags
+	and runs only if all of the prior conditions evaluated to
+	'false'
+    </description>
+  </tag>
+
+  <tag>
+    <name>param</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.xml.ParamTag</tag-class>
+    <body-content>JSP</body-content>
+    <description>
+        Adds a parameter to a containing 'transform' tag's Transformer
+    </description>
+    <attribute>
+        <name>name</name>
+        <required>true</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>value</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>parse</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.xml.ParseTag</tag-class>
+    <tei-class>org.apache.taglibs.standard.tei.XmlParseTEI</tei-class>
+    <body-content>JSP</body-content>
+    <description>
+	Parses XML content from 'source' attribute or 'body'
+    </description>
+    <attribute>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>varDom</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>scopeDom</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>xml</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>systemId</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>filter</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>set</name>
+    <tag-class>org.apache.taglibs.standard.tag.common.xml.SetTag</tag-class>
+    <body-content>empty</body-content>
+    <description>
+	Saves the result of an XPath expression evaluation in a 'scope'
+    </description>
+    <attribute>
+        <name>var</name>
+        <required>true</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+	<name>select</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>transform</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.xml.TransformTag</tag-class>
+    <tei-class>org.apache.taglibs.standard.tei.XmlTransformTEI</tei-class>
+    <body-content>JSP</body-content>
+    <description>
+	Conducts a transformation given a source XML document
+	and an XSLT stylesheet
+    </description>
+    <attribute>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>result</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>xml</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>xmlSystemId</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+	<name>xslt</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+	<name>xsltSystemId</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>when</name>
+    <tag-class>org.apache.taglibs.standard.tag.common.xml.WhenTag</tag-class>
+    <body-content>JSP</body-content>
+    <description>
+        Subtag of <choose> that includes its body if its
+        expression evalutes to 'true'
+    </description>
+    <attribute>
+        <name>select</name>
+        <required>true</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+</taglib>
diff --git a/standard/conf/x-1_0.tld b/standard/conf/x-1_0.tld
new file mode 100644
index 0000000..2237ccb
--- /dev/null
+++ b/standard/conf/x-1_0.tld
@@ -0,0 +1,273 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE taglib
+  PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
+  "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
+<taglib>
+  <tlib-version>1.0</tlib-version>
+  <jsp-version>1.2</jsp-version>
+  <short-name>x</short-name>
+  <uri>http://java.sun.com/jstl/xml</uri>
+  <display-name>JSTL XML</display-name>
+  <description>JSTL 1.0 XML library</description>
+
+  <validator>
+    <validator-class>
+	org.apache.taglibs.standard.tlv.JstlXmlTLV
+    </validator-class>
+    <init-param>
+	<param-name>expressionAttributes</param-name>
+	<param-value>
+	    out:escapeXml
+	    parse:xml
+	    parse:systemId
+	    parse:filter
+	    transform:xml
+	    transform:xmlSystemId
+	    transform:xslt
+	    transform:xsltSystemId
+	    transform:result
+	</param-value>
+	<description>
+	    Whitespace-separated list of colon-separated token pairs
+	    describing tag:attribute combinations that accept expressions.
+	    The validator uses this information to determine which
+	    attributes need their syntax validated.
+	</description>
+     </init-param>
+  </validator>
+
+  <tag>
+    <name>choose</name>
+    <tag-class>org.apache.taglibs.standard.tag.common.core.ChooseTag</tag-class>
+    <body-content>JSP</body-content>
+    <description>
+        Simple conditional tag that establishes a context for
+        mutually exclusive conditional operations, marked by
+        <when> and <otherwise>
+    </description>
+  </tag>
+
+  <tag>
+    <name>out</name>
+    <tag-class>org.apache.taglibs.standard.tag.el.xml.ExprTag</tag-class>
+    <body-content>empty</body-content>
+    <description>
+	Like <%= ... >, but for XPath expressions.
+    </description>
+    <attribute>
+        <name>select</name>
+        <required>true</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>escapeXml</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>if</name>
+    <tag-class>org.apache.taglibs.standard.tag.common.xml.IfTag</tag-class>
+    <body-content>JSP</body-content>
+    <description>
+      XML conditional tag, which evalutes its body if the
+      supplied XPath expression evalutes to 'true' as a boolean
+    </description>
+    <attribute>
+        <name>select</name>
+        <required>true</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>forEach</name>
+    <tag-class>org.apache.taglibs.standard.tag.common.xml.ForEachTag</tag-class>
+    <body-content>JSP</body-content>
+    <description>
+	XML iteration tag.
+    </description>
+    <attribute>
+	<name>var</name>
+	<required>false</required>
+	<rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+	<name>select</name>
+	<required>true</required>
+	<rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>otherwise</name>
+    <tag-class>org.apache.taglibs.standard.tag.common.core.OtherwiseTag</tag-class>
+    <body-content>JSP</body-content>
+    <description>
+	Subtag of <choose> that follows <when> tags
+	and runs only if all of the prior conditions evaluated to
+	'false'
+    </description>
+  </tag>
+
+  <tag>
+    <name>param</name>
+    <tag-class>org.apache.taglibs.standard.tag.el.xml.ParamTag</tag-class>
+    <body-content>JSP</body-content>
+    <description>
+        Adds a parameter to a containing 'transform' tag's Transformer
+    </description>
+    <attribute>
+        <name>name</name>
+        <required>true</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>value</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>parse</name>
+    <tag-class>org.apache.taglibs.standard.tag.el.xml.ParseTag</tag-class>
+    <tei-class>org.apache.taglibs.standard.tei.XmlParseTEI</tei-class>
+    <body-content>JSP</body-content>
+    <description>
+	Parses XML content from 'source' attribute or 'body'
+    </description>
+    <attribute>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>varDom</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>scopeDom</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>xml</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>systemId</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>filter</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>set</name>
+    <tag-class>org.apache.taglibs.standard.tag.common.xml.SetTag</tag-class>
+    <body-content>empty</body-content>
+    <description>
+	Saves the result of an XPath expression evaluation in a 'scope'
+    </description>
+    <attribute>
+        <name>var</name>
+        <required>true</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+	<name>select</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>transform</name>
+    <tag-class>org.apache.taglibs.standard.tag.el.xml.TransformTag</tag-class>
+    <tei-class>org.apache.taglibs.standard.tei.XmlTransformTEI</tei-class>
+    <body-content>JSP</body-content>
+    <description>
+	Conducts a transformation given a source XML document
+	and an XSLT stylesheet
+    </description>
+    <attribute>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>result</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>xml</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>xmlSystemId</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+	<name>xslt</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+	<name>xsltSystemId</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>when</name>
+    <tag-class>org.apache.taglibs.standard.tag.common.xml.WhenTag</tag-class>
+    <body-content>JSP</body-content>
+    <description>
+        Subtag of <choose> that includes its body if its
+        expression evalutes to 'true'
+    </description>
+    <attribute>
+        <name>select</name>
+        <required>true</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+</taglib>
diff --git a/standard/conf/x.tld b/standard/conf/x.tld
new file mode 100644
index 0000000..e52ffe8
--- /dev/null
+++ b/standard/conf/x.tld
@@ -0,0 +1,448 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
+    version="2.0">
+    
+  <description>JSTL 1.1 XML library</description>
+  <display-name>JSTL XML</display-name>
+  <tlib-version>1.1</tlib-version>
+  <short-name>x</short-name>
+  <uri>http://java.sun.com/jsp/jstl/xml</uri>
+
+  <validator>
+    <description>
+        Provides validation features for JSTL XML tags.
+    </description>
+    <validator-class>
+	org.apache.taglibs.standard.tlv.JstlXmlTLV
+    </validator-class>
+  </validator>
+
+  <tag>
+    <description>
+        Simple conditional tag that establishes a context for
+        mutually exclusive conditional operations, marked by
+        <when> and <otherwise>
+    </description>
+    <name>choose</name>
+    <tag-class>org.apache.taglibs.standard.tag.common.core.ChooseTag</tag-class>
+    <body-content>JSP</body-content>
+  </tag>
+
+  <tag>
+    <description>
+	Like <%= ... >, but for XPath expressions.
+    </description>
+    <name>out</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.xml.ExprTag</tag-class>
+    <body-content>empty</body-content>
+    <attribute>
+        <description>
+XPath expression to be evaluated.
+        </description>
+        <name>select</name>
+        <required>true</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Determines whether characters <,>,&,'," in the
+resulting string should be converted to their
+corresponding character entity codes. Default
+value is true.
+        </description>
+        <name>escapeXml</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+        XML conditional tag, which evalutes its body if the
+        supplied XPath expression evalutes to 'true' as a boolean
+    </description>
+    <name>if</name>
+    <tag-class>org.apache.taglibs.standard.tag.common.xml.IfTag</tag-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <description>
+The test condition that tells whether or not the
+body content should be processed.
+        </description>
+        <name>select</name>
+        <required>true</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Name of the exported scoped variable for the
+resulting value of the test condition. The type
+of the scoped variable is Boolean.
+        </description>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Scope for var.
+        </description>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+	XML iteration tag.
+    </description>
+    <name>forEach</name>
+    <tag-class>org.apache.taglibs.standard.tag.common.xml.ForEachTag</tag-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <description>
+Name of the exported scoped variable for the
+current item of the iteration. This scoped variable
+has nested visibility. Its type depends on the
+result of the XPath expression in the select
+attribute.
+        </description>
+	<name>var</name>
+	<required>false</required>
+	<rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+XPath expression to be evaluated.
+        </description>
+	<name>select</name>
+	<required>true</required>
+	<rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Iteration begins at the item located at the
+specified index. First item of the collection has
+index 0.
+        </description>
+	<name>begin</name>
+	<required>false</required>
+	<rtexprvalue>true</rtexprvalue>
+	<type>int</type>
+    </attribute>
+    <attribute>
+        <description>
+Iteration ends at the item located at the specified
+index (inclusive).
+        </description>
+	<name>end</name>
+	<required>false</required>
+	<rtexprvalue>true</rtexprvalue>
+	<type>int</type>
+    </attribute>
+    <attribute>
+        <description>
+Iteration will only process every step items of
+the collection, starting with the first one.
+        </description>
+	<name>step</name>
+	<required>false</required>
+	<rtexprvalue>true</rtexprvalue>
+	<type>int</type>
+    </attribute>
+    <attribute>
+        <description>
+Name of the exported scoped variable for the
+status of the iteration. Object exported is of type
+javax.servlet.jsp.jstl.core.LoopTagStatus. This scoped variable has nested visibility.
+        </description>
+	<name>varStatus</name>
+	<required>false</required>
+	<rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+	Subtag of <choose> that follows <when> tags
+	and runs only if all of the prior conditions evaluated to
+	'false'
+    </description>
+    <name>otherwise</name>
+    <tag-class>org.apache.taglibs.standard.tag.common.core.OtherwiseTag</tag-class>
+    <body-content>JSP</body-content>
+  </tag>
+
+  <tag>
+    <description>
+        Adds a parameter to a containing 'transform' tag's Transformer
+    </description>
+    <name>param</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.xml.ParamTag</tag-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <description>
+Name of the transformation parameter.
+        </description>
+        <name>name</name>
+        <required>true</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Value of the parameter.
+        </description>
+        <name>value</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+	Parses XML content from 'source' attribute or 'body'
+    </description>
+    <name>parse</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.xml.ParseTag</tag-class>
+    <tei-class>org.apache.taglibs.standard.tei.XmlParseTEI</tei-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <description>
+Name of the exported scoped variable for
+the parsed XML document. The type of the
+scoped variable is implementation
+dependent.
+        </description>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Name of the exported scoped variable for
+the parsed XML document. The type of the
+scoped variable is
+org.w3c.dom.Document.
+        </description>
+        <name>varDom</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Scope for var.
+        </description>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Scope for varDom.
+        </description>
+        <name>scopeDom</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Deprecated. Use attribute 'doc' instead.
+        </description>
+        <name>xml</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Source XML document to be parsed.
+        </description>
+        <name>doc</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+The system identifier (URI) for parsing the
+XML document.
+        </description>
+        <name>systemId</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Filter to be applied to the source
+document.
+        </description>
+        <name>filter</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+	Saves the result of an XPath expression evaluation in a 'scope'
+    </description>
+    <name>set</name>
+    <tag-class>org.apache.taglibs.standard.tag.common.xml.SetTag</tag-class>
+    <body-content>empty</body-content>
+    <attribute>
+        <description>
+Name of the exported scoped variable to hold
+the value specified in the action. The type of the
+scoped variable is whatever type the select
+expression evaluates to.
+        </description>
+        <name>var</name>
+        <required>true</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+XPath expression to be evaluated.
+        </description>
+	<name>select</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Scope for var.
+        </description>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+	Conducts a transformation given a source XML document
+	and an XSLT stylesheet
+    </description>
+    <name>transform</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.xml.TransformTag</tag-class>
+    <tei-class>org.apache.taglibs.standard.tei.XmlTransformTEI</tei-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <description>
+Name of the exported
+scoped variable for the
+transformed XML
+document. The type of the
+scoped variable is
+org.w3c.dom.Document.
+        </description>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Scope for var.
+        </description>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Result
+Object that captures or
+processes the transformation
+result.
+        </description>
+        <name>result</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Deprecated. Use attribute
+'doc' instead.
+        </description>
+        <name>xml</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Source XML document to be
+transformed. (If exported by
+<x:set>, it must correspond
+to a well-formed XML
+document, not a partial
+document.)
+        </description>
+        <name>doc</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Deprecated. Use attribute
+'docSystemId' instead.
+        </description>
+        <name>xmlSystemId</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+The system identifier (URI)
+for parsing the XML
+document.
+        </description>
+        <name>docSystemId</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+javax.xml.transform.Source
+Transformation stylesheet as
+a String, Reader, or
+Source object.
+        </description>
+	<name>xslt</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+The system identifier (URI)
+for parsing the XSLT
+stylesheet.
+        </description>
+	<name>xsltSystemId</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+        Subtag of <choose> that includes its body if its
+        expression evalutes to 'true'
+    </description>
+    <name>when</name>
+    <tag-class>org.apache.taglibs.standard.tag.common.xml.WhenTag</tag-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <description>
+The test condition that tells whether or
+not the body content should be
+processed
+        </description>
+        <name>select</name>
+        <required>true</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+</taglib>
diff --git a/standard/doc/conf/web.xml b/standard/doc/conf/web.xml
new file mode 100644
index 0000000..8c8dd01
--- /dev/null
+++ b/standard/doc/conf/web.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+
+<!DOCTYPE web-app
+    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
+    "http://java.sun.com/dtd/web-app_2_3.dtd">
+
+<web-app>
+
+    <description>
+      Documentation for the 'standard' tag library
+    </description>
+
+    <welcome-file-list>
+      <welcome-file>index.jsp</welcome-file>
+      <welcome-file>index.html</welcome-file>
+    </welcome-file-list>
+
+</web-app>
diff --git a/standard/doc/web/GettingStarted.html b/standard/doc/web/GettingStarted.html
new file mode 100644
index 0000000..ca1aa37
--- /dev/null
+++ b/standard/doc/web/GettingStarted.html
@@ -0,0 +1,343 @@
+<html>
+<head>
+<title>Getting Started</title>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+</head>
+
+<body bgcolor="#FFFFFF">
+<h2>Getting Started with the Standard Tag Library</h1>
+
+<p>This document describes how to get up and running quickly with the
+Standard Taglib, an implementation of the Java Server Pages™ Standard
+Tag Library (JSTL). This document may be useful to page authors and tag
+developers who are interested in JSTL's functionality.  Using the
+"standard-examples" application is also a great way to familiarize
+yourself with JSTL's functionality and use.</p>
+
+<hr />
+<h2>Introduction</h2>
+
+<a name="#1.1" /></a>
+<h3>What is JSTL?  Where does it come from?</h3>
+
+<p>JSTL is the Java Server Pages Standard Tag Library.  It is an
+effort of the Java Community Process (JCP) and comes out of the
+JSR-052 expert group.</p>
+
+<a name="#1.2" /></a>
+<h3>What does JSTL do?</h3>
+
+<p>JSTL encapsulates, as simple tags, core functionality common to many
+JSP applications.  For example, instead of suggesting that you iterate
+over lists using a scriptlet or different iteration tags from
+numerous vendors, JSTL defines a standard <forEach> tag that works
+the same everywhere.</p>
+
+<p>This standardization lets you learn a single tag and use it on multiple
+JSP containers.  Also, when tags are standard, containers can recognize
+them and optimize their implementations.</p>
+
+<p>JSTL provides support for core iteration
+and control-flow features, text inclusion, internationalizaton-capable
+formatting tags, and XML-manipulation tags.  The <i>expression language</i> that
+JSTL defined in the 1.0 version of the specification is now an integral part
+of the JSP 2.0 specification.
+Developers may also be interested in JSTL's current extensibility
+mechanisms; JSTL currently provides a framework for integrating custom
+tags with JSTL tags.</p>
+
+<h3>What has changed in this Standard taglib release?</h3>
+<p>Please see the <a href="ReleaseNotes.html">Release Notes</a> document for 
+  information on any release changes.</p>
+
+<h3>How can I learn more about JSTL</h3>
+
+<p>Sun's official JSTL page at <a
+href="http://java.sun.com/products/jstl"
+>http://java.sun.com/products/jstl</a> lists books and other
+resources that will help you learn JSTL.</p>
+
+<hr />
+<h2><a name="#2" /></a>Getting started quickly</h2>
+
+<p>JSTL 1.1 requires a JSP 2.0 container. We recommend you
+test the Standard Taglib with Tomcat 5.x. JSTL 1.0 only required 
+a JSP 1.2 container and is also available for download from
+<a href="http://jakarta.apache.org/taglibs">Jakarta Taglibs</a>.</p>
+
+<p>To install Tomcat, follow the instructions at <a
+href="http://jakarta.apache.org/tomcat">http://jakarta.apache.org/tomcat</a>.
+
+<p>To use the Standard Taglib from its Jakarta Taglibs distribution,
+simply copy the JAR files in the distribution's 'lib' directory to your
+application's WEB-INF/lib directory. The following JAR files are included 
+in the Standard Taglib distribution and need to be copied to your 
+application's WEB-INF/lib directory:</p>
+
+  <table width="95%" border="1" cellpadding="5">
+    <tr>
+      <th width="25%">Name</th>
+      <th width="40%">Description</th>
+      <th width="35%">Jar File Name</th>
+    </tr>
+    <tr>
+      <td width="25%">
+        <div align="center"><a href="http://java.sun.com/products/jstl">JSTL
+          API classes</a></div>
+      </td>
+      <td width="40%">
+        <div align="left">JSTL API classes</div>
+      </td>
+      <td width="35%">
+        <div align="center">jstl.jar</div>
+      </td>
+    </tr>
+    <tr>
+      <td width="25%">
+        <div align="center"><a href="http://java.sun.com/products/jstl">JSTL
+          implementation classes</a></div>
+      </td>
+      <td width="40%">
+        <div align="left">Standard Taglib JSTL implementation classes</div>
+      </td>
+      <td width="35%">
+        <div align="center">standard.jar</div>
+      </td>
+    </tr>
+  </table>
+
+<p>The standard tag library also has the following dependencies:</p>
+<ul>
+ <li>JAXP 1.2</li>
+ <li>Xalan 2.5</li>
+ <li>JDBC Standard Extension 2.0</li>
+</ul>
+
+<p>
+However, since all of these dependencies are included in J2SE 1.4.2 and higher, 
+it is therefore recommended to use J2SE 1.4.2 or higher to avoid having to 
+worry about these other dependencies.
+</p>
+
+<p>
+If the java platform under which you run your JSP container does not
+provide these dependencies, they must be made available either globally
+to all web-applications by your container, or individually within the
+WEB-INF/lib directory of your web-application.</p>
+
+<p>
+For convenience, these jar files have been included in directory 
+lib/old-dependencies of this distribution.</p>
+
+  <table width="95%" border="1" cellpadding="5">
+    <tr>
+      <th width="25%">Name</th>
+      <th width="40%">Description</th>
+      <th width="35%">Jar File Name</th>
+    </tr>
+    <tr>
+      <td width="25%">
+        <div align="center"><a href="http://java.sun.com/products/jdbc/download.html">JDBC
+          2.0 Optional Package </a></div>
+      </td>
+      <td width="40%">
+        <div align="left">
+          <p>JDBC implementation classes. </p>
+          <p>Already present in J2SE 1.4.</p>
+        </div>
+      </td>
+      <td width="35%">
+        <div align="center">jdbc2_0-stdext.jar</div>
+      </td>
+    </tr>
+    <tr>
+      <td width="25%">
+        <div align="center"><a href="http://java.sun.com/products/xml/jaxp">
+          JAXP 1.2 implementation</a></div>
+      </td>
+      <td width="40%">
+        <div align="left">Standard Taglib requires a JAXP 1.2 compliant parser</div>
+      </td>
+      <td width="35%">
+        <div align="center">
+          <table width="95%" border="0" align="center">
+            <tr>
+              <td width="79%"><font size="-1">example of JAXP 1.2 impl classes</font></td>
+              <td width="21%">
+                <ul>
+                  <li>jaxp-api.jar</li>
+                  <li>dom.jar</li>
+                  <li>sax.jar</li>
+                  <li>xercesImpl.jar</li>
+                </ul>
+              </td>
+            </tr>
+          </table>
+        </div>
+      </td>
+    </tr>
+    <tr>
+      <td width="25%">
+        <div align="center"><a href="http://xml.apache.org">Xalan 2.5</a></div>
+      </td>
+      <td width="40%">
+        <p>Apache XML Xalan XSLT<br>
+          Transformation Processor.<br>
+        </p>
+      </td>
+      <td width="35%">
+        <div align="center">xalan.jar</div>
+      </td>
+    </tr>
+  </table>
+
+
+
+<h3>Multiple tag libraries</h3>
+
+<p>
+The constituent tag libraries of Standard Taglib are as follows:
+</p>
+
+  <table border="1" cellpadding="5">
+    <tr> 
+      <th>Funtional Area</th>
+      <th>URI</th>
+      <th>Prefix</th>
+      <th>Example</th>
+    </tr>
+    <tr> 
+      <td>Core</td>
+      <td>http://java.sun.com/jsp/jstl/core</td>
+      <td> 
+        <div align="center"><font face="Courier New, Courier, mono">c</font></div>
+      </td>
+      <td><font face="Courier New, Courier, mono"><c:<i>tagname</i> ...></font></td>
+    </tr>
+    <tr> 
+      <td>XML processing</td>
+      <td>http://java.sun.com/jsp/jstl/xml</td>
+      <td> 
+        <div align="center"><font face="Courier New, Courier, mono">x</font></div>
+      </td>
+      <td><font face="Courier New, Courier, mono"><x:<i>tagname</i> ...></font></td>
+    </tr>
+    <tr> 
+      <td>I18N capable formatting</td>
+      <td>http://java.sun.com/jsp/jstl/fmt</td>
+      <td> 
+        <div align="center"><font face="Courier New, Courier, mono">fmt</font></div>
+      </td>
+      <td><font face="Courier New, Courier, mono"><fmt:<i>tagname</i> ...></font></td>
+    </tr>
+    <tr> 
+      <td>Database access (SQL)</td>
+      <td>http://java.sun.com/jsp/jstl/sql</td>
+      <td> 
+        <div align="center"><font face="Courier New, Courier, mono">sql</font></div>
+      </td>
+      <td><font face="Courier New, Courier, mono"><sql:<i>tagname</i> ...></font></td>
+    </tr>
+    <tr> 
+      <td>Functions</td>
+      <td>http://java.sun.com/jsp/jstl/functions</td>
+      <td> 
+        <div align="center"><font face="Courier New, Courier, mono">fn</font></div>
+      </td>
+      <td><font face="Courier New, Courier, mono">fn:<i>functionName</i>(...)</font></td>
+    </tr>
+  </table>
+
+<p>Using the Standard Taglib libraries is simple; you simply need to import
+them into your JSP pages using the <b>taglib</b> directive.  For
+instance, to import the 'core' JSTL library into your page, you would
+include the following line at the top of your JSP page, as
+follows:</p>
+
+<pre>
+    <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
+</pre>
+
+<h3>Expression language</h3>
+
+<p>The EL makes it easy for page authors to
+access and manipulate application data. 
+For an overview of the EL, see 
+Chapter 3 of the <a href="http://java.sun.com/products/jstl">JSTL Specification</a>.</p>
+
+<h3>Topics covered in JSTL </h3>
+
+<p>As we mentioned above, JSTL includes core tags to support iteration,
+conditionals, and expression-language support. It also supports EL functions 
+for string manipulation. For more information on
+precisely how these tags work, you should read the <a
+href="http://java.sun.com/products/jstl">JSTL specification</a>.  Here, we
+just offer a quick roadmap of each feature in order to help orient
+you.</p>
+
+<dl> 
+  <dt><b>Iteration</b></dt>
+  <dd>The core iteration tag is <forEach>, which iterates over most collections 
+    and similar objects you'd think to iterate over. <forTokens> lets you 
+    iterate over tokens in a <tt>String</tt> object; it lets you specify the <tt>String</tt> 
+    and the delimiters.</dd>
+  <dt><b>Conditionals</b></dt>
+  <dd>JSTL supports a simple conditional <if> tag along with a collection 
+    of tags -- <choose>, <when>, and <otherwise> -- that support 
+    mutually exclusive conditionals. These latter three tags let you implement 
+    a typical <tt>if/else if/else if/else</tt> structure.</dd>
+  <dt> <b>Expression language</b></dt>
+  <dd>JSTL provides a few tags to facilitate use of the expression language. <out> 
+    prints out the value of a particular expression in the current EL, similar 
+    to the way that the scriptlet expression (<%= ... %>) syntax prints 
+    out the value of a expression in the scripting language (typically Java). 
+    <set> lets you set a scoped attribute (e.g., a value in the request, 
+    page, session, or application scopes) with the value of an expression.</dd>
+  <dt> <b>Text inclusion</b></dt>
+  <dd>JSP supports the <tt>jsp:include</tt> tag, but this standard action is limited 
+    in that it only supports relative URLs. JSTL introduces the <tt>c:import</tt> 
+    tag, which lets you retrieve absolute URLs. For instance, you can use <tt>c:import</tt> 
+    to retrieve information from the web using HTTP URLs, or from a file server 
+    using an FTP URL. The tag also has some advanced support for performance optimizations, 
+    avoiding unnecessary buffering of data that's retrieved.</dd>
+  <dt> <b>I18N-capable text formatting</b></dt>
+  <dd>Formatting data is one of the key tasks in many JSP pages. JSTL introduces 
+    tags to support data formatting and parsing. These tags rely on convenient 
+    machinery to support internationalized applications. </dd>
+  <dt> <b>XML manipulation</b></dt>
+  <dd>You can't look anywhere these days without seeing XML, and JSTL gives you 
+    convenient support for manipulating it from your JSP pages. Parse documents, 
+    use XPath to select content, and perform XSLT transformations from within 
+    your JSP pages.</dd>
+  <dt><b>Database access</b></dt>
+  <dd>Easily access relational databases using the SQL actions. You can perform database queries, easily access results, perform updates, and group several operations into a transaction.</dd>
+  <dt><b>Functions</b></dt>
+  <dd>String manipulations can be performed using the functions provided in
+JSTL.</dd>
+  <dt> </dt>
+</dl>
+
+<h3>For tag developers...</h3>
+
+<p>Developers of custom tags should also read the <a
+href="http://java.sun.com/products/jstl">JSTL specification</a>. JSTL
+defines some abstract classes that assist with rapid development of tags
+and promote integration of custom tags with JSTL's tag set.</p>
+
+<p>For instance, extending
+<tt>javax.servlet.jsp.jstl.core.ConditionalTagSupport</tt> lets you write a
+conditional tag by merely implementing a single method that returns a
+<tt>boolean</tt> value correspondent with your tag's desired conditional
+behavior; also, this base class promotes JSTL's recommended model of
+conditional-tag design.</p>
+
+<p>Similarly, <tt>javax.servlet.jsp.jstl.core.IteratorTagSupport</tt> lets
+you easily implement iteration tags.  The handlers for the <forEach>
+and <forTokens> tags extend this class and thus implement the
+<tt>javax.servlet.jsp.jstl.core.IteratorTag</tt> interface, which provides
+a well-defined mechanism for iteration tags to communicate with custom
+subtags you can write.  See the "standard-examples" application for one
+example of how you might use such custom subtags.</p>
+
+</body>
+</html>
diff --git a/standard/doc/web/ReleaseNotes.html b/standard/doc/web/ReleaseNotes.html
new file mode 100644
index 0000000..7244f6d
--- /dev/null
+++ b/standard/doc/web/ReleaseNotes.html
@@ -0,0 +1,750 @@
+<html>
+<head>
+<title>Standard 1.1 Release Notes</title>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+</head>
+
+<body bgcolor="#FFFFFF">
+<center>
+<h1>
+Standard: An Implementation of the JSP™ Standard Tag Library (JSTL)<br>
+<p>
+Version: 1.1.2<br>
+Release Notes
+</h1>
+</center>
+
+<p>The Standard 1.1.2 release is an implementation of the <a href="http://java.sun.com/products/jstl">JSTL 1.1 Specification</a>.</p>
+
+<p>The Standard Taglib, which is hosted at Apache, is used as the source repository for the <a href="http://java.sun.com/products/jstl">JSTL reference implementation</a> supplied by Sun Microsystems, Inc.</p>
+<hr/>
+
+<h2>Release History</h2>
+
+
+<dt><b>October 2004 &#x2022; Standard 1.1.2</b></dt>
+<p>The latest implementation is available from the Nightly Builds.</p>
+  <dd>Bugs fixed since Standard 1.1.1 Taglib release:</dd>
+  <ul>
+  <blockquote>
+    <table width="95%" border="1">
+      <tr>
+        <th width="27%">
+          <div align="center">
+            Bug Id</div>
+        </th>
+        <th width="73%">Summary</th>
+      </tr>
+      <tr>
+        <td width="27%" height="15">
+          <div align="center">
+          <a href="http://nagoya.apache.org/bugzilla/show_bug.cgi?id=17388">17388</a></div>
+        </td>
+        <td width="73%" height="15">
+          <p>Close statement created in update tag. It is good programming pro-active to close statements as soon as they are finished even though they will also be closed when the connection that created them is closed.</p> 
+        </td>
+      </tr>
+      <tr>
+        <td width="27%" height="15">
+          <div align="center">
+          <a href="http://nagoya.apache.org/bugzilla/show_bug.cgi?id=31313">31313</a></div>
+        </td>
+        <td width="73%" height="15">
+          <p>According to the W3C document the schemaLocation declaration is made up of a pair of URI references.  One defines the namespace name and the other is a hint as to the location of the schema document.  The space in the schemaLocation definition separates the two declarations.<p>
+          <p>For a complete explanation you can take a look at Section 4.3.2 of <a href=http://www.w3.org/TR/xmlschema-1/#schema-loc">W3C Xml Schema Document</a>
+          <p>In the JSTL case the location is not an absolute URI which can be confusing especially to some IDE's. Went ahead and changed it to be an absolute URI pointing to the schema document location.</p>
+        </td>
+      </tr>
+      <tr>
+        <td width="27%" height="15">
+          <div align="center">
+          <a href="http://nagoya.apache.org/bugzilla/show_bug.cgi?id=30646">30646</a></div>
+        </td>
+        <td width="73%" height="15">
+          <p>Fixed implementation so that it compiles under J2SE 5.0. Changed the J2SE 5.0 reserved keyword "enum" to "enum_".</p> 
+          <p>NOTE: the JAXP 1.2 classes will need to be specified with J2SE 5.0 since the the 5.0 bundled JAXP 1.3 packages have been moved around and re-named.</p>
+        </td>
+      </tr>
+      <tr>
+        <td width="27%" height="15">
+          <div align="center">
+          <a href="http://nagoya.apache.org/bugzilla/show_bug.cgi?id=30647">30647</a></div>
+        </td>
+        <td width="73%" height="15">
+          <p>Followed the <a href="http://java.sun.com/blueprints/code/projectconventions.html">BluePrints Guidelines</a> for web application project structure. Most IDEs assume the BluePrints structure so abiding by these guidelines will help them integrate the examples.</p>
+          <p>The following changes were made to the examples directory structure:</p>
+          <ul>
+            <li>moved the examples deployment descriptor to the web/WEB-INF directory out from conf</li>
+            <li>moved the jstl-examples.tld to web/WEB-INF/tlds</li>
+            <li>updated build.xml to reflect new directory structure</li>
+          </ul>
+        </td>
+      </tr>
+      <tr>
+        <td width="27%" height="15">
+          <div align="center">
+          <a href="http://nagoya.apache.org/bugzilla/show_bug.cgi?id=31147">31147</a></div>
+        </td>
+        <td width="73%" height="15">
+          <p>Fixed XPath Expression evaluation so that the expressions are evaluated relative to the document Node as opposed to the document Root.</p>
+        </td>
+      </tr>
+    </table>
+  </blockquote>
+  </ul>
+    <blockquote>
+      <p>Other changes and additions:</p>
+      <ul>
+        <li>In JstlUriResolver when external entitities are resolved the 'base' varies from different Xalan implementations. Fixed how base is handled.</li>
+      </ul>
+    </blockquote>
+
+
+<dt><b>July 2004 &#x2022; Standard 1.1.1</b></dt><br>
+  <dd>Bugs fixed since Standard 1.1.0 Taglib release:</dd>
+  <ul>
+  <blockquote>
+    <table width="95%" border="1">
+      <tr>
+        <th width="27%">
+          <div align="center">
+            Bug Id</div>
+        </th>
+        <th width="73%">Summary</th>
+      </tr>
+      <tr>
+        <td width="27%" height="15">
+          <div align="center">
+          <a href="http://nagoya.apache.org/bugzilla/show_bug.cgi?id=16773">16773</a></div>
+        </td>
+        <td width="73%" height="15">Substituted static values where Boolean objects were created.</td>
+      </tr>
+      <tr>
+        <td width="27%" height="15">
+          <div align="center">
+          <a href="http://nagoya.apache.org/bugzilla/show_bug.cgi?id=25382">25382</a></div>
+        </td>
+        <td width="73%" height="15">Optimization of the xml escaping used by JSTL Functions and the out tag handlers.</td>
+      </tr>
+      <tr>
+        <td width="27%" height="15">
+          <div align="center">
+          <a href="http://nagoya.apache.org/bugzilla/show_bug.cgi?id=25967">25967</a></div>
+        </td>
+        <td width="73%" height="15">Removed synchronization on getEvaluatorByName() method. Now synchronizing on nameMap and allowing reads to occur without blocking. Should be a performance improvement.</td>
+      </tr>
+      <tr>
+        <td width="27%" height="15">
+          <div align="center">
+          <a href="http://nagoya.apache.org/bugzilla/show_bug.cgi?id=26614">26614</a></div>
+        </td>
+        <td width="73%" height="15">Remove quotes from prefix when throwing an exception</td>
+      </tr>
+    </table>
+  </blockquote>
+  </ul>
+    <blockquote>
+      <p>Other changes and additions:</p>
+      <ul>
+        <li>Fixed Core TLV to allow EL and RT based actions to be mixed as allowed by the JSTL specification.</li>
+        <li>Trimmed sql dataSource attribute tokens so any spaces in the comma delimited list are ignored.</li>
+        <li>Added Junit and Cactus testing framework. Documentation is in README_src.txt available in the source distribution.</li>
+        <li>Updated licenses to the new Apache License, Version 2.0.</li>
+      </ul>
+    </blockquote>
+<dt><b>January 2004 • Standard 1.1.0</b>
+<p>
+This is a complete implementation of the JSTL 1.1 Maintenance Release.
+<p>
+<dd>Bugs fixed since Standard 1.1.0-B1 Taglib release:</dd>
+<ul>
+  <blockquote>
+    <table width="95%" border="1">
+      <tr>
+        <th width="27%">
+          <div align="center">Bug Id</div>
+        </th>
+        <th width="73%">Summary</th>
+      </tr>
+      <tr>
+        <td width="27%" height="15">
+          <div align="center"><a
+href="http://nagoya.apache.org/bugzilla/show_bug.cgi?id=15703">15703</a></div>
+        </td>
+        <td width="73%" height="15">Illegal scope attribute without var in "fmt:setLocale" tag</td>
+      </tr>
+      <tr>
+        <td width="27%" height="15">
+          <div align="center"><a
+href="http://nagoya.apache.org/bugzilla/show_bug.cgi?id=24892">24892</a></div>
+        </td>
+        <td width="73%" height="15">ResultImpl should implement java.io.Serializable</td>
+      </tr>
+      <tr>
+        <td width="27%" height="15">
+          <div align="center"><a
+href="http://nagoya.apache.org/bugzilla/show_bug.cgi?id=25637">25637</a></div>
+        </td>
+        <td width="73%" height="15">IteratorTagSupport example is missing </td>
+      </tr>
+      <tr>
+        <td width="27%" height="15">
+          <div align="center"><a
+href="http://nagoya.apache.org/bugzilla/show_bug.cgi?id=22860">22860</a></div>
+        </td>
+        <td width="73%" height="15">tag url generate invalid result for root context</td>
+      </tr>
+      <tr>
+        <td width="27%" height="15">
+          <div align="center"><a
+href="http://nagoya.apache.org/bugzilla/show_bug.cgi?id=24597">24597</a></div>
+        </td>
+        <td width="73%" height="15">accept-language header missing and fallback locale</td>
+      </tr>
+      <tr>
+        <td width="27%" height="15">
+          <div align="center"><a
+href="http://nagoya.apache.org/bugzilla/show_bug.cgi?id=24863">24863</a></div>
+        </td>
+        <td width="73%" height="15">permittedTaglibs.tld and scriptfree.tld do not validate in xml parser</td>
+      </tr>
+      <tr>
+        <td width="27%" height="15">
+          <div align="center"><a
+href="http://nagoya.apache.org/bugzilla/show_bug.cgi?id=25638">25638</a></div>
+        </td>
+        <td width="73%" height="15">Xml filter example doesn't work</td>
+      </tr>
+      <tr>
+        <td width="27%" height="15">
+          <div align="center"><a
+href="http://nagoya.apache.org/bugzilla/show_bug.cgi?id=26320">26320</a></div>
+        </td>
+        <td width="73%" height="15"><c:out> doesn't work properly when tag handlers are pooling</td>
+      </tr>
+    </table>
+  </blockquote>
+</ul>
+
+<blockquote> 
+  <p>Other changes and additions:</p>
+  <ul>
+    <li>Regarding bug #24892, it's important to note that relying on the serializability of Result objects might not be portable across different implementations of the JSTL spec. Also, ResultImpl will be serializable only if the values returned by the ResultSet are serializable too, which depends on the JDBC driver being used.
+  </ul>
+</blockquote>
+
+
+<dt><b>September 2003 • Standard 1.1.0-B1</b></dt>
+<p>
+This is a complete implementation of the JSTL 1.1 Maintenance Release.
+<p>
+<dd>Bugs fixed since Standard 1.0.3 Taglib release:</dd>
+<ul>
+  <blockquote>
+    <table width="95%" border="1">
+      <tr>
+        <th width="27%">
+          <div align="center">Bug Id</div>
+        </th>
+        <th width="73%">Summary</th>
+      </tr>
+      <tr>
+        <td width="27%" height="15">
+          <div align="center"><a
+href="http://nagoya.apache.org/bugzilla/show_bug.cgi?id=18498">18498</a></div>
+        </td>
+        <td width="73%" height="15">
+fmt:formatNumber now removes the scoped variable when the
+value is null or empty.
+        </td>
+      </tr>
+      <tr>
+        <td width="27%" height="15">
+          <div align="center"><a
+href="http://nagoya.apache.org/bugzilla/show_bug.cgi?id=16912">16912</a></div>
+        </td>
+        <td width="73%" height="15">
+c:param now encodes URL with URLEncoder.encode(str, encoding)
+        </td>
+      </tr>
+      <tr>
+        <td width="27%" height="15">
+          <div align="center"><a
+href="http://nagoya.apache.org/bugzilla/show_bug.cgi?id=17388">17388</a></div>
+        </td>
+        <td width="73%" height="15">
+PreparedStatement used in sql:query closed immediately after use to avoid leaks.
+        </td>
+      </tr>
+      <tr>
+        <td width="27%" height="15">
+          <div align="center"><a
+href="http://nagoya.apache.org/bugzilla/show_bug.cgi?id=10024">10024</a></div>
+        </td>
+        <td width="73%" height="15">
+Advisory character encoding now properly fetched from "charset" attribute
+of "content-type" header (required change to spec)</td>
+      </tr>    
+      <tr>
+        <td width="27%" height="15">
+          <div align="center"><a
+href="http://nagoya.apache.org/bugzilla/show_bug.cgi?id=17440">17440</a></div>
+        </td>
+        <td width="73%" height="15">
+Fixed processing of Locale when variant is used.
+        </td>
+      </tr>    
+      <tr>
+        <td width="27%" height="15">
+          <div align="center"><a
+href="http://nagoya.apache.org/bugzilla/show_bug.cgi?id=20197">20197</a></div>
+        </td>
+        <td width="73%" height="15">
+<sql:setDataSource> did not allow the specification of a scope without
+a var attribute to set the SQl DataSource configuration setting. Fixed.
+        </td>
+      </tr>    
+      <tr>
+        <td width="27%" height="15">
+          <div align="center"><a
+href="http://nagoya.apache.org/bugzilla/show_bug.cgi?id=22034">22034</a></div>
+        </td>
+        <td width="73%" height="15">
+Page scope not properly set with <c:if>. Fixed.
+        </td>
+      </tr>    
+      <tr>
+        <td width="27%" height="15">
+          <div align="center"><a
+href="http://nagoya.apache.org/bugzilla/show_bug.cgi?id=21188">21188</a></div>
+        </td>
+        <td width="73%" height="15">
+Config.find() fails on invalidated sessions. Fixed.
+        </td>
+      </tr>    
+      <tr>
+        <td width="27%" height="15">
+          <div align="center"><a
+href="http://nagoya.apache.org/bugzilla/show_bug.cgi?id=16775">16775</a></div>
+        </td>
+        <td width="73%" height="15">
+Consistent use JspTagException: (1) always include original exception when
+available. (2) use ex.toString() instead of getMessage().
+        </td>
+      </tr>    
+      <tr>
+        <td width="27%" height="15">
+          <div align="center"><a
+href="http://nagoya.apache.org/bugzilla/show_bug.cgi?id=22188">22188</a></div>
+        </td>
+        <td width="73%" height="15">
+Type conversion rules now properly applied when setting a bean property using
+<c:set>.
+        </td>
+      </tr>    
+    </table>
+  </blockquote>
+</ul>
+
+<blockquote> 
+  <p>Other changes and additions:</p>
+  <ul>
+    <li>Added Version class to easily tell the version of the jar file.</li>
+    <li>Added a few sample cases to highlight url rewriting and encoding.</li>
+    <li>New sample JSP page demoing I18N-Formatting capabilities.</li>
+    <li>Our dependency on jaxen and saxpath has been removed by switching
+        our XPath support to Xalan.</li>
+    <li>Added attribute descriptions in the TLDs.</li>
+    <li>javax.servlet.jsp.jstl.sql.ResultImpl now implements java.io.Serializable,
+and insert a comment in the Release Notes stating that relying on the
+serializability of Result objects might not be portable across
+different implementations of the JSTL spec
+  </ul>
+</blockquote>
+
+
+<dt><b>February 2003 • Standard 1.0.3</b></dt>
+<p><dd>Bugs fixed since Standard 1.0.2 Taglib release:</dd>
+<ul>
+  <blockquote>
+    <table width="95%" border="1">
+      <tr>
+        <th width="27%">
+          <div align="center">Bug Id</div>
+        </th>
+        <th width="73%">Summary</th>
+      </tr>
+      <tr>
+        <td width="27%" height="15">
+          <div align="center"><a
+href="http://nagoya.apache.org/bugzilla/show_bug.cgi?id=16069">16069</a></div>
+        </td>
+        <td width="73%" height="15">
+        Tag-handler reuse discovered a bug in <c:out>'s processing of default
+        values.  This bug was fixed by initializing an instance variable
+        in doStartTag().
+        </td>
+      </tr>
+      <tr>
+        <td width="27%" height="15">
+          <div align="center"><a
+href="http://nagoya.apache.org/bugzilla/show_bug.cgi?id=8694">8694</a></div>
+        </td>
+        <td width="73%" height="15">We revisited this bug prompted by a
+report from a user of the J2EE RI and adjusted the EL implementation to
+accommodate the J2EE RI's default security restrictions.
+        </td>
+      </tr>
+      <tr>
+        <td width="27%" height="15">
+          <div align="center"><a
+href="http://nagoya.apache.org/bugzilla/show_bug.cgi?id=15977">15977</a></div>
+        </td>
+        <td width="73%" height="15">
+	Minor display-related bug in ScriptFreeTLV
+        </td>
+      </tr>
+      <tr>
+        <td width="27%" height="15">
+          <div align="center"><a
+href="http://nagoya.apache.org/bugzilla/show_bug.cgi?id=14695">14695</a></div>
+        </td>
+        <td width="73%" height="15">
+There still was a bug when the <code>fmt:message</code> tag was pooled 
+and reused, and a bundle was not specified explicitely.
+        </td>
+      </tr>
+      <tr>
+        <td width="27%" height="15">
+          <div align="center"><a href="http://nagoya.apache.org/bugzilla/show_bug.cgi?id=15169">15169</a></div>
+        </td>
+        <td width="73%" height="15">
+Added <code><uri></code> definition in WEB-INF/jstl-examples.tld for
+/jstl-examples-taglib.
+        </td>
+      </tr>
+      <tr>
+        <td width="27%" height="15">
+          <div align="center"><a href="http://nagoya.apache.org/bugzilla/show_bug.cgi?id=15495">15495</a></div>
+        </td>
+        <td width="73%" height="15">
+If <c:set> is used to set a property of a bean, and a setter method 
+does not exist for that bean, a NullPointerException was thrown.
+A JspException with an appropriate error message is now thrown instead.
+        </td>
+      </tr>
+      <tr>
+        <td width="27%" height="15">
+          <div align="center"><a href="http://nagoya.apache.org/bugzilla/show_bug.cgi?id=15621">15621</a></div>
+        </td>
+        <td width="73%" height="15">
+The tag handler for <fmt:requestEncoding> was not resetting the encoding value it picks up from the
+javax.servlet.jsp.jstl.fmt.request.charset session attribute between invokations.
+        </td>
+      </tr>
+      <tr>
+        <td width="27%" height="15">
+          <div align="center"><a
+href="http://nagoya.apache.org/bugzilla/show_bug.cgi?id=15873">15873</a></div>
+        </td>
+        <td width="73%" height="15">
+We now expose the exception object thrown by a bean property evaluated by the
+EL (not just the exception message).
+        </td>
+      </tr>
+      <tr>
+        <td width="27%" height="15">
+          <div align="center"><a
+href="http://nagoya.apache.org/bugzilla/show_bug.cgi?id=16377">16377</a></div>
+        </td>
+        <td width="73%" height="15">
+Improved the exception message when there is a failure accessing an absolute URL.
+        </td>
+      </tr>
+      <tr>
+        <td width="27%" height="15">
+          <div align="center"><a
+href="http://nagoya.apache.org/bugzilla/show_bug.cgi?id=16379">16379</a></div>
+        </td>
+        <td width="73%" height="15">
+Fixed minor typos in standard-examples.
+        </td>
+      </tr>
+    </table>
+  </blockquote>
+</ul>
+<blockquote> 
+  <p>Other changes and additions:</p>
+  <ul>
+    <li>Fixed minor typos in JSTL API Javadoc documentation.</li>
+    <li>Added TLV examples (scriptFree and PermittedTaglibs)</li>
+    <li>Fixed minor typo on standard/examples/web/xml/ForEach.jsp</li>
+    <li>Improved Japanese localization</li>
+  </ul>
+</blockquote>
+
+<dt><b>13 October 2002 • Standard 1.0.2 Taglib released</b></dt>
+<p>
+<dd>Bugs fixed since Standard 1.0.1 Taglib release:</dd>
+<ul>
+  <blockquote>
+    <table width="95%" border="1">
+      <tr>
+        <th width="27%">
+          <div align="center">Bug Id</div>
+        </th>
+        <th width="73%">Summary</th>
+      </tr>
+      <tr>
+        <td width="27%" height="15">
+          <div align="center"><a href="http://nagoya.apache.org/bugzilla/show_bug.cgi?id=11204">11204</a></div>
+        </td>
+        <td width="73%" height="15">The <code>fmt</code> tags used to store the <code>BodyContent</code>
+          from one tag in the same field variable they use for <code>value</code>. This caused problems
+          in a container that supported tag re-use since the old <code>BodyContent</code> was used.</td>
+      </tr>
+      <tr>
+        <td width="27%" height="15">
+          <div align="center"><a href="http://nagoya.apache.org/bugzilla/show_bug.cgi?id=11293">11293</a></div>
+        </td>
+        <td width="73%" height="15">The <code>xml:transform</code> tag can now be used with a series of imported
+          stylesheets.</td>
+      </tr>
+      <tr>
+        <td width="27%" height="15">
+          <div align="center"><a href="http://nagoya.apache.org/bugzilla/show_bug.cgi?id=12333">12333</a></div>
+        </td>
+        <td width="73%" height="15">There was a bug in the EL grammar that caused attribute values like <tt>"$${X}"</tt> to be parsed as a single string instead of a string followed by an expression.</td>
+      </tr>
+      <tr>
+        <td width="27%" height="15">
+          <div align="center"><a href="http://nagoya.apache.org/bugzilla/show_bug.cgi?id=12963">12963</a></div>
+        </td>
+        <td width="73%" height="15">The <code><c:url></code> <code>value</code> attribute and the <code>
+          <c:redirect></code> <code>url</code> attribute are required as defined in the JSTL specification.</td>
+      </tr>
+      <tr>
+        <td width="27%" height="15">
+          <div align="center"><a href="http://nagoya.apache.org/bugzilla/show_bug.cgi?id=13405">13405</a></div>
+        </td>
+        <td width="73%" height="15">According to the JDBC specification, a null can be passed to the <code>PreparedStatement.setObject()</code> and the parameter will be set to JDBC NULL properly. The broken <code>PreparedStatment.setNull()</code> call has been removed.
+        </td>
+      </tr>
+      <tr>
+        <td width="27%" height="15">
+          <div align="center"><a href="http://nagoya.apache.org/bugzilla/show_bug.cgi?id=13518">13518</a></div>
+        </td>
+        <td width="73%" height="15">There was a typographical error in our sample TLDs for the PermittedTaglibTLV and ScriptFreeTLV validators.
+        </td>
+      </tr>
+    </table>
+  </blockquote>
+</ul>
+<blockquote> 
+  <p>Other changes and additions:</p>
+  <ul>
+    <li>Wrapped number formatting examples that use browser-based locale inside <c:catch>. Now the parse 
+      exception that occurs with "de_DE" locale due to a bug in <code>java.text.NumberFormat</code> 
+      (Bugtraq bugid: 4709840) can be documented appropriately.
+    </li>
+    <li>The "jsp20el.build" target was modified so that the JSTP 2.0 EL packages were renamed to avoid potential
+      JSTL 1.0 conflict.
+    </li>
+    <li>Root cause now exposed when an EL expression evaluation fails.
+    </li>
+    <li>New regression tests for the EL parser.</li>
+  </ul>
+</blockquote>
+
+<dt><b>26 July 2002 • Standard 1.0.1 Taglib released</b></dt>
+<p><dd>Bugs fixed since Standard 1.0 Taglib 
+Final release: </dd>
+</blockquote>
+<ul>
+  <blockquote> 
+    <table width="95%" border="1">
+      <tr> 
+        <th width="27%"> 
+          <div align="center">Bug Id</div>
+        </th>
+        <th width="73%">Summary</th>
+      </tr>
+      <tr> 
+        <td width="27%" height="15"> 
+          <div align="center"><a href="http://nagoya.apache.org/bugzilla/show_bug.cgi?id=8723">8723</a></div>
+        </td>
+        <td width="73%" height="15">Fixed '<code>xslt</code>' attribute for <code><x:transform></code> 
+          to only accept an<br>
+          object exported by <code><x:parse></code> if it's a <code>String</code>, 
+          <code>Reader</code>, or<br>
+          <code>javax.xml.transform.Source</code>.</td>
+      </tr>
+      <tr> 
+        <td width="27%" height="15"> 
+          <div align="center"><a href="http://nagoya.apache.org/bugzilla/show_bug.cgi?id=9257">9257</a></div>
+        </td>
+        <td width="73%" height="15">Added <code>"UNICODE_INPUT = true"</code> 
+          to the <code>ELParser.jj</code><br>
+          options so that non-ascii values can be parsed.</td>
+      </tr>
+      <tr> 
+        <td width="27%"> 
+          <div align="center"><a href="http://nagoya.apache.org/bugzilla/show_bug.cgi?id=9528">9528</a></div>
+        </td>
+        <td width="73%"><code>GettingStarted.html</code> guide updated to include 
+          all jar dependency information. </td>
+      </tr>
+      <tr> 
+        <td width="27%"> 
+          <div align="center"><a href="http://nagoya.apache.org/bugzilla/show_bug.cgi?id=9581">9581</a></div>
+        </td>
+        <td width="73%">SQL examples updated to allow for the inputting of <code>dataSource</code> 
+          username and password.</td>
+      </tr>
+      <tr> 
+        <td width="27%"> 
+          <div align="center"><a href="http://nagoya.apache.org/bugzilla/show_bug.cgi?id=9968">9968</a></div>
+        </td>
+        <td width="73%"><code>c:url</code> tag no longer prepends path to page 
+          relative URLs. </td>
+      </tr>
+      <tr> 
+        <td width="27%"> 
+          <div align="center"><a href="http://nagoya.apache.org/bugzilla/show_bug.cgi?id=10175">10175</a></div>
+        </td>
+        <td width="73%">Added a <code><welcome-file-list></code> element 
+          to the example application's deployment descriptor. Modified <code>standard-doc</code> 
+          in a corresponding fashion.</td>
+      </tr>
+      <tr> 
+        <td width="27%" height="32"> 
+          <div align="center"><a href="http://nagoya.apache.org/bugzilla/show_bug.cgi?id=10334">10334</a></div>
+        </td>
+        <td width="73%" height="32"> 
+          <p><code>BundleSupport</code> modified to use the current context classloader 
+            instead of the classloader that loaded it. This change was necessary 
+            in order for <code>BundleSupport</code> to properly find resources 
+            in a web application.</p>
+          <p>The SQL <code>DataSourceWrapper</code> also modified to properly 
+            use classloader delegation to load resources.</p>
+        </td>
+      </tr>
+      <tr> 
+        <td width="27%"> 
+          <div align="center"><a href="http://nagoya.apache.org/bugzilla/show_bug.cgi?id=10856">10856</a></div>
+        </td>
+        <td width="73%">Fixed incorrect <code>x:param</code> error message.</td>
+      </tr>
+    </table>
+  </blockquote>
+</ul>
+<blockquote> 
+  <p>Other changes and additions:</p>
+  <ul>
+    <li>Improved <code>x:parse</code> action's <code>EntityResolver</code> to 
+      work with JAXP 1.2. URI's normalized so they can be processed consistently.</li>
+    <li> The <a href="http://java.sun.com/products/jstl">JSTL 1.0 Specification</a> 
+      has all the official functional descriptions; out of date documentation 
+      removed.</li>
+    <li>Hard-coded and browser-based locales separated into distinct pages in 
+      order to avoid conflicting response encodings.</li>
+    <li>Formatting web application examples updated to use EL to access request 
+      parameters.</li>
+    <li><code>query</code> and <code>update </code>tags modified to catch a more 
+      generic JDBC driver implementation generated exception when it occurs and 
+      provide a meaningful error message.</li>
+    <li><code>DateParam</code> tag modified to have an empty body content as defined 
+      by the spec.</li>
+    <li><code>PreparedStatement.setNull(parameterIndex, java.sql.Types.NULL)</code> 
+      now used when specifying null parameter values.</li>
+    <li>XPath performance improved by caching parsed representations of XPath 
+      expressions.</li>
+    <li>Support for relative system ID's in <code><x:transform></code> simplified.</li>
+    <li>Improved <code>TimeZoneSupport</code> javadocs</li>
+    <li>Added Japanese resources</li>
+    <li>Added support for <a href="http://www.jcp.org/jsr/detail/152.jsp">JSP 
+      2.0</a> functionality in the JSTL EL. By default, none of the new features 
+      are enabled in order to comply with the <a href="http://java.sun.com/products/jstl">JSTL 
+      1.0 Specification</a>. The functionality will be triggered by a particular 
+      way of calling the interpreter. 
+      <ul>
+        <li>Created new new "<code>jsp20</code>" parser directory. </li>
+        <li>Added new "<code>jsp20e</code>l" build target for <a href="http://www.jcp.org/jsr/detail/152.jsp">JSP 
+          2.0</a> specific features. </li>
+        <li>Added copy of <code>*.properties</code> to <a href="http://www.jcp.org/jsr/detail/152.jsp">JSP 
+          2.0</a> EL jar.</li>
+      </ul>
+    </li>
+  </ul>
+</blockquote>
+<dt><b>21 Jun 2002</b></dt>
+<dd>Final Standard Taglib 1.0 release</dd>
+
+<p><dt><b>17 Jun 2002</b></dt>
+<dd>Standard Taglib RC1 released.</dd>
+<dd> </dd>
+
+<dt><b>19 Apr 2002 </b></dt>
+<dd>Standard 1.0 Beta2 released, which is compliant with the <a href="http://jcp.org/aboutJava/communityprocess/first/jsr052/">JSTL Proposed Final Draft</a>.</dd>
+
+<p><dt><b>12 Mar 2002 </b></dt>
+<dd>Standard 1.0 Beta1 released, which is compliant with the <a href="http://jcp.org/aboutJava/communityprocess/review/jsr052/">JSTL Public Review Draft</a>.</dd>
+
+<p><dt><b>12 Dec 2001</b></dt>
+<dd>Standard 1.0 EA3 released.  Version includes the following
+changes and additions:
+<ul>
+ <li>Introduction of SQL tags ("sql:*" library).</li>
+ <li>A performance improvement to the XML "transform" tag.</li>
+ <li>Minor changes and bug fixes to the i18n and XML libraries.</li>
+ <li>Distribution JAR files are now 'standard.jar' (RI) and 'jstl.jar'
+     (API).</li>
+ <li>showSource.jsp no longer depends on raw file I/O (and so 
+     should work even when standard-examples is deployed as a WAR).</li> 
+</ul>
+</dd>
+
+<dt><b>21 Nov 2001</b></dt>
+<dd>Standard 1.0 EA2 introduced.  Version includes the following
+major changes and additions:
+<ul>
+ <li>JSPTL has been renamed to JSTL.</li>
+ <li>The "jsptl" library at Jakarta Taglibs has been renamed to
+     "standard."</li>
+ <li>Tags for text inclusion and URL encoding introduced.</li>
+ <li>Tags for i18n-capable text formatting introduced.</li>
+ <li>Tags for XML manipulation introduced.</li>
+ <li>JSTL now divides functionality among multiple TLDs.  Each TLD represents
+     a cohesive unit of functionality, such as "XML manipulation" and
+     "formatting."  'jx' and 'jr' are no longer used; they are replaced
+     with shorter abbreviations for the common cases (e.g., 'c', 'x').
+ <li>ECMAScript is now the default expression evaluator.  Since the
+     first release of 1.0 EA1, new languages include JXPath and ECMAScript.</li>
+ <li>The RI has been thoroughly repackaged; many classes have moved.</li>
+ <li>The package name for the JSTL API is now javax.servlet.jsp.jstl
+     and is subdivided into cohesive packages.  (The old package for the
+     API was javax.servlet.jsptl.)</li>
+ <li>A small number of minor changes were made to the code.  By and large,
+     these changes are not significant; the easiest way to discover
+     further details is to look at the CVS archive itself.</li>
+</ul>
+</dd>
+
+<p><dt><b>09 Oct 2001</b></dt>
+<dd>JSTL 1.0 EA1 RI, version 1.2, introduced.  This version includes support
+for ECMAScript.</dd>
+
+<p><dt><b>23 Jul 2001</b></dt>
+<dd>JSTL 1.0 EA1 RI, version 1.1, is released.  This version is compatible
+with Tomcat 4.0 B6 and Tomcat 4.0 release.</dd>
+
+<p><dt><b>10 Jul 2001</b></dt>
+<dd>JSTL 1.0 EA1 RI first made available for download.</dd>
+
+<p><dt><b>08 Jul 2001</b></dt>
+<dd>Initial version of JSTL RI contributed by JSR-052 Expert Group and imported 
+  into Jakarta CVS archive.</dd>
+
+
+</body>
+</html>
diff --git a/standard/doc/web/index.html b/standard/doc/web/index.html
new file mode 100644
index 0000000..e8fcba3
--- /dev/null
+++ b/standard/doc/web/index.html
@@ -0,0 +1,83 @@
+<html>
+<head>
+<title>Standard: An Implementation of the JSP™ Standard Tag Library (JSTL)</title>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+</head>
+
+<body bgcolor="#FFFFFF">
+<h2>Standard: An Implementation of the JavaServer Pages™ Standard Tag Library
+(JSTL)</h2>
+
+
+<h3>Included in this distribution:</h3>
+
+<h4>Documentation ('doc/web' directory)</h4>
+
+<ul>
+  <li><a href="GettingStarted.html">Getting Started</a>: A quick roadmap to help 
+    you get started with this release.</li>
+  <li><a href="ReleaseNotes.html">Release Notes</a>: Release history of the Standard Taglib.</li>
+</ul>
+
+Sun's <a href="http://java.sun.com/products/jstl">JSTL web site</a>
+    is the official website for JSTL, providing access to the specification 
+(the specification is a formal description of the functionality and 
+      features of the JSTL tag set), as well as 
+lists several tutorials and books about JSTL that are available.
+
+
+<h4>Examples ('examples' directory)</h4>
+
+<p>	The standard-examples application included with this distribution
+	demonstrates the current capabilities of JSTL, exploring idioms
+	and usage patterns when appropriate.</p>
+
+<h4>Implementation of JSTL ('src' and 'conf' directories)</h4>
+
+<p>	Every effort has been made to provide a functional, robust, and
+	speedy implementation of JSTL.
+        For developers, the code is commented thoroughly
+	to help provide an understanding of design considerations and
+	salient implementation details.</p>
+
+<p>	Classes in any of the subpackages of javax.servlet.jsp.jstl represent
+        JSTL API classes. Classes under org.apache.* represent implementation
+        classes. The implementation's package structure is organized as
+        follows:</p>
+
+<pre>
+  org.apache.taglibs.standard
+   .tag         tag handlers and routines related to them
+      .common      handlers and support routines common for RT/EL attributes
+          .core    core library (common)
+          .fmt     i18n-capable formatting tags (common)
+          .xml     XML manipulation library (common)
+	  .sql	   SQL library (common)
+      .el          handlers specific to expression language (EL) evaluation
+          .core    core library (EL)
+          .fmt     i18n-capable formatting tags (EL)
+          .xml     XML manipulation library (EL)
+	  .sql	   SQL library (EL)
+      .rt          handlers specific to rtexprvalue (rt) evaluation
+          .core    core library (rt)
+          .fmt     i18n-capable formatting tags (rt)
+          .xml     XML manipulation library (rt)
+	  .sql	   SQL library (rt)
+   .functions   EL Functions library
+   .tei         TagExtraInfo classes (common to both libraries)
+   .tlv         TagLibraryValidator classes (and associated helpers)
+   .lang        expression-language support and implementation
+      .support     ExpressionEvaluator, ExpressionEvaluatorManager
+      .jstl        JSTL 1.0 expression language
+   .resources   Resources for internationalization
+</pre>
+
+<p> The <tt>javax.servlet.jsp.jstl.*</tt> tree is discussed in the JSTL
+specification.</p>
+
+<p>Enjoy!</p>
+
+<pre>
+  -- Shawn Bayern <bayern at essentially.net>
+     (on behalf of <a href="mailto:jsr-52-comments at jcp.org">JSR-052 (JSTL) Expert Group</a>)
+</pre>
diff --git a/standard/examples/src/org/apache/taglibs/standard/examples/beans/Address.java b/standard/examples/src/org/apache/taglibs/standard/examples/beans/Address.java
new file mode 100644
index 0000000..b6855d0
--- /dev/null
+++ b/standard/examples/src/org/apache/taglibs/standard/examples/beans/Address.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.examples.beans;
+
+/**
+ * Object that represents a Customer.
+ *
+ * @author Pierre Delisle
+ * @version $Revision: 1.2 $ $Date: 2004/02/28 01:01:41 $
+ */
+
+public class Address {
+    
+    //*********************************************************************
+    // Instance variables
+    
+    /** Holds value of property line1. */
+    private String line1;
+    
+    /** Holds value of property line2. */
+    private String line2;
+    
+    /** Holds value of property city. */
+    private String city;
+    
+    /** Holds value of property zip. */
+    private String zip;
+
+    /** Holds value of property state. */
+    private String state;
+    
+    /** Holds value of property country. */
+    private String country;
+    
+    //*********************************************************************
+    // Constructor
+    
+    public Address(String line1, String line2, String city,
+    String state, String zip, String country) {
+        setLine1(line1);
+        setLine2(line2);
+        setCity(city);
+        setState(state);
+        setZip(zip);
+        setCountry(country);
+    }
+    
+    //*********************************************************************
+    // Accessors
+    
+    /** Getter for property line1.
+     * @return Value of property line1.
+     */
+    public String getLine1() {
+        return line1;
+    }
+    
+    /** Setter for property line1.
+     * @param line1 New value of property line1.
+     */
+    public void setLine1(String line1) {
+        this.line1 = line1;
+    }
+    
+    /** Getter for property line2.
+     * @return Value of property line2.
+     */
+    public String getLine2() {
+        return line2;
+    }
+    
+    /** Setter for property line2.
+     * @param line2 New value of property line2.
+     */
+    public void setLine2(String line2) {
+        this.line2 = line2;
+    }
+    
+    /** Getter for property city.
+     * @return Value of property city.
+     */
+    public String getCity() {
+        return city;
+    }
+    
+    /** Setter for property city.
+     * @param city New value of property city.
+     */
+    public void setCity(String city) {
+        this.city = city;
+    }
+    
+    /** Getter for property zip.
+     * @return Value of property zip.
+     */
+    public String getZip() {
+        return zip;
+    }
+    
+    /** Setter for property zip.
+     * @param zip New value of property zip.
+     */
+    public void setZip(String zip) {
+        this.zip = zip;
+    }
+    
+    /** Getter for property country.
+     * @return Value of property country.
+     */
+    public String getCountry() {
+        return country;
+    }
+    
+    /** Setter for property country.
+     * @param country New value of property country.
+     */
+    public void setCountry(String country) {
+        this.country = country;
+    }
+    
+    /** Getter for property state.
+     * @return Value of property state.
+     */
+    public String getState() {
+        return state;
+    }
+    
+    /** Setter for property state.
+     * @param state New value of property state.
+     */
+    public void setState(String state) {
+        this.state = state;
+    }
+    
+    //*********************************************************************
+    // Utility Methods
+    
+    /**
+     * Return a String representation of this object.
+     */
+    public String toString() {
+        StringBuffer sb = new StringBuffer();
+        sb.append(line1).append(" ");
+        sb.append(city).append(" ");
+        sb.append(country);
+        return (sb.toString());
+    } 
+}
diff --git a/standard/examples/src/org/apache/taglibs/standard/examples/beans/Customer.java b/standard/examples/src/org/apache/taglibs/standard/examples/beans/Customer.java
new file mode 100644
index 0000000..60db211
--- /dev/null
+++ b/standard/examples/src/org/apache/taglibs/standard/examples/beans/Customer.java
@@ -0,0 +1,221 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.examples.beans;
+
+import java.util.Date;
+import java.text.*;
+
+/**
+ * Object that represents a Customer.
+ *
+ * @author Pierre Delisle
+ * @version $Revision: 1.3 $ $Date: 2004/02/28 01:01:41 $
+ */
+
+public class Customer {
+    
+    //*********************************************************************
+    // Instance variables
+    
+    /** Holds value of property key. */
+    int key;
+    
+    /** Holds value of property lastName. */
+    private String lastName;
+    
+    /** Holds value of property firstName. */
+    private String firstName;
+    
+    /** Holds value of property birthDate. */
+    private Date birthDate;
+    
+    /** Holds value of property address. */
+    private Address address;
+       
+    /** Holds value of property phoneHome. */
+    private String phoneHome;
+    
+    /** Holds value of property phoneCell. */
+    private String phoneCell;
+    
+    static DateFormat df = new SimpleDateFormat("MM/dd/yyyy");
+    
+    //*********************************************************************
+    // Constructors
+    
+    public Customer() {}
+    
+    public Customer(int key,
+    String lastName,
+    String firstName,
+    Date birthDate,
+    Address address,
+    String phoneHome,
+    String phoneCell) {
+        init(key, lastName, firstName, birthDate, address, phoneHome, phoneCell);
+    }
+    
+    public void init(int key,
+    String lastName,
+    String firstName,
+    Date birthDate,
+    Address address,
+    String phoneHome,
+    String phoneCell) {
+        setKey(key);
+        setLastName(lastName);
+        setFirstName(firstName);
+        setBirthDate(birthDate);
+        setAddress(address);
+        setPhoneHome(phoneHome);
+        setPhoneCell(phoneCell);
+    }
+    
+    //*********************************************************************
+    // Properties
+    
+    /**
+     * Getter for property key.
+     * @return Value of property key.
+     */
+    public int getKey() {
+        return key;
+    }
+    
+    /**
+     * Setter for property key.
+     * @param key New value of property key.
+     */
+    public void setKey(int key) {
+        this.key = key;
+    }
+    
+    /**
+     * Getter for property lastName.
+     * @return Value of property lastName.
+     */
+    public String getLastName() {
+        return lastName;
+    }
+    
+    /**
+     * Setter for property lastName.
+     * @param lastName New value of property lastName.
+     */
+    public void setLastName(String lastName) {
+        this.lastName = lastName;
+    }
+    
+    /**
+     * Getter for property firstName.
+     * @return Value of property firstName.
+     */
+    public String getFirstName() {
+        return firstName;
+    }
+    
+    /**
+     * Setter for property firstName.
+     * @param firstName New value of property firstName.
+     */
+    public void setFirstName(String firstName) {
+        this.firstName = firstName;
+    }
+    
+    /**
+     * Getter for property birthDate.
+     * @return Value of property birthDate.
+     */
+    public Date getBirthDate() {
+        return birthDate;
+    }
+    
+    /**
+     * Setter for property birthDate.
+     * @param birthDate New value of property birthDate.
+     */
+    public void setBirthDate(Date birthDate) {
+        this.birthDate = birthDate;
+    }
+    
+    /**
+     * Getter for property address.
+     * @return Value of property address.
+     */
+    public Address getAddress() {
+        return address;
+    }
+    
+    /**
+     * Setter for property address.
+     * @param address New value of property address.
+     */
+    public void setAddress(Address address) {
+        this.address = address;
+    }
+    
+    /**
+     * Getter for property phoneHome.
+     * @return Value of property phoneHome.
+     */
+    public String getPhoneHome() {
+        return phoneHome;
+    }
+    
+    /**
+     * Setter for property phoneHome.
+     * @param phoneHome New value of property phoneHome.
+     */
+    public void setPhoneHome(String phoneHome) {
+        this.phoneHome = phoneHome;
+    }
+    
+    /**
+     * Getter for property phoneCell.
+     * @return Value of property phoneCell.
+     */
+    public String getPhoneCell() {
+        return phoneCell;
+    }
+    
+    /**
+     * Setter for property phoneCell.
+     * @param phoneCell New value of property phoneCell.
+     */
+    public void setPhoneCell(String phoneCell) {
+        this.phoneCell = phoneCell;
+    }
+    
+    //*********************************************************************
+    // Utility Methods
+    
+    /**
+     * Return a String representation of this object.
+     */
+    public String toString() {
+        StringBuffer sb = new StringBuffer();
+        sb.append("[").append(key).append("] ");
+        sb.append(getLastName()).append(", ");
+        sb.append(getFirstName()).append("  ");
+        sb.append(df.format(getBirthDate())).append("  ");
+        sb.append(getAddress()).append("  ");
+        if(getPhoneHome() != null) sb.append(getPhoneHome()).append("  ");
+        if(getPhoneCell() != null) sb.append(getPhoneCell());
+        return (sb.toString());
+    }
+}
+
diff --git a/standard/examples/src/org/apache/taglibs/standard/examples/beans/Customers.java b/standard/examples/src/org/apache/taglibs/standard/examples/beans/Customers.java
new file mode 100644
index 0000000..4ade103
--- /dev/null
+++ b/standard/examples/src/org/apache/taglibs/standard/examples/beans/Customers.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.examples.beans;
+
+import java.util.*;
+import java.text.*;
+
+/**
+ * Customers Datastore.
+ *
+ * @author Pierre Delisle
+ * @version $Revision: 1.3 $ $Date: 2004/02/28 01:01:41 $
+ */
+
+public class Customers {
+    
+    //*********************************************************************
+    // Instance variables
+    
+    private static Vector customers = new Vector();
+    private static int nextSeqNo = 0;
+    
+    //*********************************************************************
+    // Datastore operations
+    
+    public static void create(
+    String lastName,
+    String firstName,
+    String birthDate,
+    String line1,
+    String line2,
+    String city,
+    String state,
+    String zip,
+    String country) {
+        create(lastName, firstName, birthDate, line1, line2, city, state, zip,
+        country, null, null);
+    }
+    
+    /**
+     *  Create new customer
+     */
+    public static void create(
+    String lastName,
+    String firstName,
+    String birthDate,
+    String line1,
+    String line2,
+    String city,
+    String state,
+    String zip,
+    String country,
+    String phoneHome,
+    String phoneCell) {
+        Customer customer =
+        new Customer(++nextSeqNo, lastName, firstName,
+        genDate(birthDate), genAddress(line1, line2, city, state, zip, country),
+        phoneHome, phoneCell);
+        customers.add(customer);
+    }
+    
+    /**
+     * Find all customers
+     */
+    public static Collection findAll() {
+        return customers;
+    }
+    
+    //*********************************************************************
+    // Utility methods
+    
+    private static Date genDate(String dateString) {
+        DateFormat df = new SimpleDateFormat("M/d/y");
+        Date date;
+        try {
+            date = df.parse(dateString);
+        } catch (Exception ex) {
+            date = null;
+        }
+        return date;
+    }
+    
+    private static Address genAddress(String line1, String line2, String city,
+    String state, String zip, String country) {
+        return new Address(line1, line2, city, state, zip, country);
+    }
+}
diff --git a/standard/examples/src/org/apache/taglibs/standard/examples/i18n/Resources.java b/standard/examples/src/org/apache/taglibs/standard/examples/i18n/Resources.java
new file mode 100644
index 0000000..4048dc5
--- /dev/null
+++ b/standard/examples/src/org/apache/taglibs/standard/examples/i18n/Resources.java
@@ -0,0 +1,23 @@
+package org.apache.taglibs.standard.examples.i18n;
+
+import java.util.ListResourceBundle;
+
+public class Resources extends ListResourceBundle {
+    private static Object[][] contents;
+
+    static {
+	contents = new Object[][] {
+	    { "greetingMorning", "Good Morning!" },
+	    { "greetingEvening", "Good Evening!" },
+	    { "serverInfo", "Name/Version of Servlet Container: {0}, "
+	                    + "Java Version: {1}" },
+	    { "currentTime", "Current time: {0}" },
+	    { "com.acme.labels.cancel", "Cancel" },
+	    { "java.lang.ArithmeticException", "division by 0" }
+	};
+    }
+
+    public Object[][] getContents() {
+	return contents;
+    }
+}
diff --git a/standard/examples/src/org/apache/taglibs/standard/examples/i18n/Resources_de.java b/standard/examples/src/org/apache/taglibs/standard/examples/i18n/Resources_de.java
new file mode 100644
index 0000000..100b881
--- /dev/null
+++ b/standard/examples/src/org/apache/taglibs/standard/examples/i18n/Resources_de.java
@@ -0,0 +1,23 @@
+package org.apache.taglibs.standard.examples.i18n;
+
+import java.util.ListResourceBundle;
+
+public class Resources_de extends ListResourceBundle {
+    private static Object[][] contents;
+
+    static {
+	contents = new Object[][] {
+	    { "greetingMorning", "Guten Morgen!" },
+	    { "greetingEvening", "Guten Abend!" },
+	    { "serverInfo", "Name/Version des Servlet Containers: {0}, "
+	                    + "Java Version: {1}" },
+	    { "currentTime", "Heutiges Datum und Uhrzeit: {0}" },
+	    { "com.acme.labels.cancel", "Abbrechen" },
+	    { "java.lang.ArithmeticException", "/ durch 0" }
+	};
+    }
+
+    public Object[][] getContents() {
+	return contents;
+    }
+}
diff --git a/standard/examples/src/org/apache/taglibs/standard/examples/i18n/Resources_fr.java b/standard/examples/src/org/apache/taglibs/standard/examples/i18n/Resources_fr.java
new file mode 100644
index 0000000..ddd2dc1
--- /dev/null
+++ b/standard/examples/src/org/apache/taglibs/standard/examples/i18n/Resources_fr.java
@@ -0,0 +1,23 @@
+package org.apache.taglibs.standard.examples.i18n;
+
+import java.util.ListResourceBundle;
+
+public class Resources_fr extends ListResourceBundle {
+    private static Object[][] contents;
+
+    static {
+	contents = new Object[][] {
+	    { "greetingMorning", "Bonjour!!" },
+	    { "greetingEvening", "Bonsoir!" },
+	    { "serverInfo", "Nom/Version du Servlet Container: {0}, "
+	                    + "Version Java: {1}" },
+	    { "currentTime", "Nous sommes le: {0}" },
+	    { "com.acme.labels.cancel", "Annuler" },
+	    { "java.lang.ArithmeticException", "division par 0" }
+	};
+    }
+
+    public Object[][] getContents() {
+	return contents;
+    }
+}
diff --git a/standard/examples/src/org/apache/taglibs/standard/examples/i18n/Resources_it.java b/standard/examples/src/org/apache/taglibs/standard/examples/i18n/Resources_it.java
new file mode 100644
index 0000000..c02f61e
--- /dev/null
+++ b/standard/examples/src/org/apache/taglibs/standard/examples/i18n/Resources_it.java
@@ -0,0 +1,17 @@
+package org.apache.taglibs.standard.examples.i18n;
+
+import java.util.ListResourceBundle;
+
+public class Resources_it extends ListResourceBundle {
+    private static Object[][] contents;
+
+    static {
+	contents = new Object[][] {
+	    { "greetingMorning", "Buon giorno!" }
+	};
+    }
+
+    public Object[][] getContents() {
+	return contents;
+    }
+}
diff --git a/standard/examples/src/org/apache/taglibs/standard/examples/startup/Init.java b/standard/examples/src/org/apache/taglibs/standard/examples/startup/Init.java
new file mode 100644
index 0000000..6ea1737
--- /dev/null
+++ b/standard/examples/src/org/apache/taglibs/standard/examples/startup/Init.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.examples.startup;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+
+import org.apache.taglibs.standard.examples.beans.Customers;
+
+/**
+ * Initialization class. Builds all the data structures
+ * used in the "examples" webapp.
+ *
+ * @author Pierre Delisle
+ * @version $Revision: 1.4 $ $Date: 2004/08/16 21:38:27 $
+ */
+public class Init implements ServletContextListener {
+    
+    //*********************************************************************
+    // ServletContextListener methods
+    
+    // recovers the one context parameter we need
+    public void contextInitialized(ServletContextEvent sce) {
+        //p("contextInitialized");
+        init(sce);
+    }
+    
+    public void contextDestroyed(ServletContextEvent sce) {
+        //p("contextInitialized");
+    }
+    
+    //*********************************************************************
+    // Initializations
+    
+    private void init(ServletContextEvent sce) {
+        /*
+         *  Customers
+         */
+        Customers.create("Richard", "Maurice", "5/15/35",
+        "123 Chemin Royal", "Appt. #301",
+        "Montreal", "QC", "H3J 9R9", "Canada");
+        Customers.create("Mikita", "Stan", "12/25/47",
+        "45 Fisher Blvd", "Suite 203",
+        "Chicago", "IL", "65982", "USA", "(320)876-9784", null);
+        Customers.create("Gilbert", "Rod", "3/11/51",
+        "123 Main Street", "",
+        "New-York City", "NY", "19432", "USA");
+        Customers.create("Howe", "Gordie", "7/25/46",
+        "7654 Wings Street", "",
+        "Detroit", "MG", "07685", "USA", "(465)675-0761", "(465)879-9802");
+        Customers.create("Sawchuk", "Terrie", "11/05/46",
+        "12 Maple Leafs Avenue", "",
+        "Toronto", "ON", "M5C 1Z1", "Canada");
+        sce.getServletContext().setAttribute("customers", Customers.findAll());
+
+	/**
+	 * Array of primitives (int)
+	 */
+	int[] intArray = new int[] {10, 20, 30, 40, 50};
+        sce.getServletContext().setAttribute("intArray", intArray);
+
+	/**
+	 * Array of Objects (String)
+	 */
+	String[] stringArray = new String[] {
+	    "A first string",
+	    "La deuxieme string",
+	    "Ella troisiemo stringo",
+	};
+        sce.getServletContext().setAttribute("stringArray", stringArray);
+
+	/**
+        * String-keyed Map
+        */
+        Hashtable stringMap = new Hashtable();
+        sce.getServletContext().setAttribute("stringMap", stringMap);
+        stringMap.put("one", "uno");
+        stringMap.put("two", "dos");
+        stringMap.put("three", "tres");
+        stringMap.put("four", "cuatro");
+        stringMap.put("five", "cinco");
+        stringMap.put("six", "seis");
+        stringMap.put("seven", "siete");
+        stringMap.put("eight", "ocho");
+        stringMap.put("nine", "nueve");
+        stringMap.put("ten", "diez");
+
+        /**
+         * Integer-keyed Map
+	 */
+	// we use a Hashtable so we can get an Enumeration easily, below
+        Hashtable numberMap = new Hashtable();
+	sce.getServletContext().setAttribute("numberMap", numberMap);
+	numberMap.put(new Integer(1), "uno");
+	numberMap.put(new Integer(2), "dos");
+	numberMap.put(new Integer(3), "tres");
+	numberMap.put(new Integer(4), "cuatro");
+	numberMap.put(new Integer(5), "cinco");
+	numberMap.put(new Integer(6), "seis");
+	numberMap.put(new Integer(7), "siete");
+	numberMap.put(new Integer(8), "ocho");
+	numberMap.put(new Integer(9), "nueve");
+	numberMap.put(new Integer(10), "diez");
+
+	/**
+	 * Enumeration
+	 */
+	Enumeration enum_ = numberMap.keys();
+	// don't use 'enum' for attribute name because it is a 
+	// reserved word in EcmaScript.
+        sce.getServletContext().setAttribute("enumeration", enum_);
+
+	/**
+	 * Message arguments for parametric replacement
+	 */
+	Object[] serverInfoArgs =
+	    new Object[] {
+		sce.getServletContext().getServerInfo(),
+		System.getProperty("java.version")
+	    };
+	sce.getServletContext().setAttribute("serverInfoArgs", serverInfoArgs);
+    }
+    
+    //*********************************************************************
+    // Initializations
+    
+    private void p(String s) {
+        System.out.println("[Init] " + s);
+    }
+}
diff --git a/standard/examples/src/org/apache/taglibs/standard/examples/taglib/CustomerFmtTag.java b/standard/examples/src/org/apache/taglibs/standard/examples/taglib/CustomerFmtTag.java
new file mode 100644
index 0000000..00b53ab
--- /dev/null
+++ b/standard/examples/src/org/apache/taglibs/standard/examples/taglib/CustomerFmtTag.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.examples.taglib;
+
+import java.io.IOException;
+
+import javax.servlet.jsp.*;
+import javax.servlet.jsp.tagext.*;
+import javax.servlet.jsp.jstl.core.*;
+
+import org.apache.taglibs.standard.examples.beans.Customer;
+
+/**
+ * <p>Tag handler for <customerFmt>
+ *
+ * @author Pierre Delisle
+ * @version $Revision: 1.3 $ $Date: 2004/02/28 01:01:41 $
+ */
+public class CustomerFmtTag extends TagSupport {
+    
+    //*********************************************************************
+    // Instance variables
+    
+    /** Holds value of property customer. */
+    private Customer customer;
+    
+    /** Holds value of property fmt. */
+    private String fmt;
+    
+    //*********************************************************************
+    // Constructors
+    
+    public CustomerFmtTag() {
+        super();
+        init();
+    }
+    
+    private void init() {
+        customer = null;
+        fmt = null;
+    }    
+    
+    //*********************************************************************
+    // TagSupport methods
+    
+    public int doStartTag() throws JspException {
+        JspWriter out = pageContext.getOut();
+        try {
+            if (fmt.equalsIgnoreCase("short")) {
+                out.println(customer.getFirstName() + " " +
+                customer.getLastName());
+            } else if (fmt.equalsIgnoreCase("long")) {
+                out.println(customer.getFirstName() + " " +
+                customer.getLastName() + " " + customer.getAddress());
+            } else {
+                out.println("invalid format");
+            }
+        } catch (IOException ex) {}
+        
+        return SKIP_BODY;
+    }
+    
+    // Releases any resources we may have (or inherit)
+    public void release() {
+        super.release();
+        init();
+    }
+    
+    //*********************************************************************
+    // Accessors
+    
+    /**
+     * Getter for property customer.
+     * @return Value of property customer.
+     */
+    public Customer getCustomer() {
+        return customer;
+    }
+    
+    /**
+     * Setter for property customer.
+     * @param customer New value of property customer.
+     */
+    public void setCustomer(Customer customer) {
+        this.customer = customer;
+    }
+    
+    /**
+     * Getter for property fmt.
+     * @return Value of property fmt.
+     */
+    public String getFmt() {
+        return fmt;
+    }
+    
+    /**
+     * Setter for property fmt.
+     * @param fmt New value of property fmt.
+     */
+    public void setFmt(String fmt) {
+        this.fmt = fmt;
+    }    
+}
diff --git a/standard/examples/src/org/apache/taglibs/standard/examples/taglib/DefaultLocaleTag.java b/standard/examples/src/org/apache/taglibs/standard/examples/taglib/DefaultLocaleTag.java
new file mode 100644
index 0000000..83a74fe
--- /dev/null
+++ b/standard/examples/src/org/apache/taglibs/standard/examples/taglib/DefaultLocaleTag.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.examples.taglib;
+
+import java.util.Locale;
+
+import javax.servlet.jsp.JspTagException;
+import javax.servlet.jsp.jstl.core.ConditionalTagSupport;
+
+/**
+ * <p>Tag handler for <locales>
+ *
+ * @author Felipe Leme <jstl at felipeal.net>
+ * @version $Revision: 1.3 $ $Date: 2004/02/28 01:01:41 $
+ */
+
+public class DefaultLocaleTag extends ConditionalTagSupport {
+
+  private static final Locale defaultLocale = Locale.getDefault();
+
+  public boolean condition() throws JspTagException {   
+    LocalesTag localesTag = (LocalesTag) findAncestorWithClass( this, LocalesTag.class );
+    if ( localesTag == null ) {
+      throw new JspTagException( "defaultLocale bust be inside locales");
+    }
+    return localesTag.getCurrent().equals( defaultLocale );
+   }
+}
diff --git a/standard/examples/src/org/apache/taglibs/standard/examples/taglib/EscapeHtmlTag.java b/standard/examples/src/org/apache/taglibs/standard/examples/taglib/EscapeHtmlTag.java
new file mode 100644
index 0000000..1443cf2
--- /dev/null
+++ b/standard/examples/src/org/apache/taglibs/standard/examples/taglib/EscapeHtmlTag.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.examples.taglib;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.io.Writer;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.JspTagException;
+import javax.servlet.jsp.tagext.BodyTagSupport;
+
+import org.apache.taglibs.standard.examples.util.Util;
+
+/**
+ * <p>Tag handler for <escapeHtml>
+ *
+ * @author Pierre Delisle
+ * @version $Revision: 1.3 $ $Date: 2004/02/28 01:01:41 $
+ */
+public class EscapeHtmlTag extends BodyTagSupport {
+    
+    //*********************************************************************
+    // Instance variables
+    
+    private Object reader;
+    private Object writer;
+    
+    //*********************************************************************
+    // Constructors
+    
+    public EscapeHtmlTag() {
+        super();
+        init();
+    }
+    
+    private void init() {
+        reader = null;
+        writer = null;
+    }
+    
+    
+    //*********************************************************************
+    // Tag's properties
+    
+    /**
+     * Tag's 'reader' attribute
+     */
+    public void setReader(Object reader) {
+        this.reader = reader;
+    }
+    
+    /**
+     * Tag's 'writer' attribute
+     */
+    public void setWriter(Object writer) {
+        this.writer = writer;
+    }
+    
+    //*********************************************************************
+    // TagSupport methods
+    
+    public int doEndTag() throws JspException {
+        Reader in;
+        Writer out;
+        
+        if (reader == null) {
+            String bcs = getBodyContent().getString().trim();
+            if (bcs == null || bcs.equals("")) {
+                throw new JspTagException("In <escapeHtml>, 'reader' " +
+                "not specified and no non-whitespace content inside the tag.");
+            }
+            in = Util.castToReader(bcs);
+        } else {
+            in = Util.castToReader(reader);
+        }
+        
+        if (writer == null) {
+            out = pageContext.getOut();
+        } else {
+            out = Util.castToWriter(writer);
+        }
+        
+        transform(in, out);
+        return EVAL_PAGE;
+    }
+    
+    /**
+     * Releases any resources we may have (or inherit)
+     */
+    public void release() {
+        super.release();
+        init();
+    }
+    
+    //*********************************************************************
+    // Tag's scific behavior methods
+    
+    /**
+     * Transform
+     */
+    public void transform(Reader reader, Writer writer)
+    throws JspException {
+        int c;
+        try {
+            writer.write("<pre>");
+            while ((c = reader.read()) != -1) {
+                if (c == '<') {
+                    writer.write("<");
+                } else if (c == '>') {
+                    writer.write(">");
+                } else {
+                    writer.write(c);
+                }
+            }
+            writer.write("</pre>");
+        } catch (IOException ex) {
+            throw new JspException("EscapeHtml: " +
+            "error copying chars", ex);
+        }
+    }
+}
diff --git a/standard/examples/src/org/apache/taglibs/standard/examples/taglib/EvenTag.java b/standard/examples/src/org/apache/taglibs/standard/examples/taglib/EvenTag.java
new file mode 100644
index 0000000..7aac8ab
--- /dev/null
+++ b/standard/examples/src/org/apache/taglibs/standard/examples/taglib/EvenTag.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.examples.taglib;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.JspTagException;
+import javax.servlet.jsp.jstl.core.LoopTag;
+import javax.servlet.jsp.tagext.TagSupport;
+
+/**
+ * <p>Tag handler for <odd>
+ *
+ * @author Pierre Delisle
+ * @version $Revision: 1.3 $ $Date: 2004/02/28 01:01:41 $
+ */
+public class EvenTag extends TagSupport {
+    
+    //*********************************************************************
+    // TagSupport methods
+    
+    public int doStartTag() throws JspException {
+        LoopTag iteratorTag = (LoopTag)findAncestorWithClass(
+        this, LoopTag.class);
+        if (iteratorTag == null) {
+            throw new JspTagException("<even> must be nested within a LoopTag");
+        }
+        
+        int count = iteratorTag.getLoopStatus().getCount();
+        return (count % 2 == 0) ? EVAL_BODY_INCLUDE : SKIP_BODY;
+    }
+}
diff --git a/standard/examples/src/org/apache/taglibs/standard/examples/taglib/FileTag.java b/standard/examples/src/org/apache/taglibs/standard/examples/taglib/FileTag.java
new file mode 100644
index 0000000..73f50f0
--- /dev/null
+++ b/standard/examples/src/org/apache/taglibs/standard/examples/taglib/FileTag.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.examples.taglib;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.tagext.TagSupport;
+
+/**
+ * <p>Tag handler for <file>
+ *
+ * @author Pierre Delisle
+ * @version $Revision: 1.3 $ $Date: 2004/02/28 01:01:41 $
+ */
+public class FileTag extends TagSupport {
+    
+    //*********************************************************************
+    // Instance variables
+    
+    private String id;
+    private String file;
+    
+    private Reader reader;
+    
+    //*********************************************************************
+    // Constructors
+    
+    public FileTag() {
+        super();
+        init();
+    }
+    
+    private void init() {
+        id = null;
+        file = null;
+    }
+    
+    //*********************************************************************
+    // Tag's properties
+    
+    /**
+     * Tag's 'id' attribute
+     */
+    public void setId(String id) {
+        this.id = id;
+    }
+    
+    /**
+     * Tag's 'file' attribute
+     */
+    public void setfile(String file) {
+        this.file = file;
+    }
+    
+    //*********************************************************************
+    // TagSupport methods
+    
+    public int doStartTag() throws JspException {
+        reader = getReaderFromFile(file);
+        exposeVariable(reader);
+        return EVAL_BODY_INCLUDE;
+    }
+    
+    public int doEndTag() throws JspException {
+        try {
+            reader.close();
+        } catch (IOException ex) {}
+        reader = null;
+        return EVAL_PAGE;
+    }
+    
+    /**
+     * Releases any files we may have (or inherit)
+     */
+    public void release() {
+        super.release();
+        init();
+    }
+    
+    //*********************************************************************
+    // Tag's specific behavior methods
+    
+    public Reader getReaderFromFile(String name) throws JspException {
+        InputStream in = pageContext.getServletContext().
+            getResourceAsStream(name);
+        if (in == null) {
+            throw new JspException("Could not access " + name);
+        }
+
+        return new InputStreamReader(in);
+    }
+
+    
+    //*********************************************************************
+    // Utility methods
+        
+    private void exposeVariable(Reader reader) {
+        if (id != null) {
+            pageContext.setAttribute(id, reader);
+        }
+    }
+}
diff --git a/standard/examples/src/org/apache/taglibs/standard/examples/taglib/Functions.java b/standard/examples/src/org/apache/taglibs/standard/examples/taglib/Functions.java
new file mode 100644
index 0000000..f725467
--- /dev/null
+++ b/standard/examples/src/org/apache/taglibs/standard/examples/taglib/Functions.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.examples.taglib;
+
+import java.lang.reflect.Array;
+
+import javax.servlet.jsp.JspTagException;
+
+/**
+ * <p>Exmaples taglib Functions</p>
+ * 
+ * @author Pierre Delisle
+ */
+
+public class Functions {
+
+    /**
+     * Display the collection types supported by c:forEach.
+     */
+    public static String display(Object obj) throws JspTagException {
+        if (obj == null) return "";         
+        if (obj instanceof String) return obj.toString();
+        /*
+        if (obj instanceof Collection) {
+            return "FIXME";
+        }
+        if (obj instanceof Map) {
+            return "FIXME";
+        }        
+        if (obj instanceof Iterator) {
+            Iterator iter = (Iterator)obj;
+            while (iter.hasNext()) {
+                iter.next();
+            }
+            return "FIXME";
+        }            
+        if (obj instanceof Enumeration) {
+            Enumeration enum_ = (Enumeration)obj;
+            while (enum_.hasMoreElements()) {
+                enum_.nextElement();
+            }
+            return "FIXME";
+        }
+        */
+        try {
+            StringBuffer buf = new StringBuffer();
+            int count = Array.getLength(obj);
+            for (int i=0; i<count; i++) {
+                buf.append(Array.get(obj, i).toString());
+                if (i<count-1) buf.append("<font color='red'> • </font>");
+            }
+            return buf.toString();
+        } catch (IllegalArgumentException ex) {}
+        throw new JspTagException("Bad Item");        
+    }      
+}
diff --git a/standard/examples/src/org/apache/taglibs/standard/examples/taglib/LocalesTag.java b/standard/examples/src/org/apache/taglibs/standard/examples/taglib/LocalesTag.java
new file mode 100644
index 0000000..8245f76
--- /dev/null
+++ b/standard/examples/src/org/apache/taglibs/standard/examples/taglib/LocalesTag.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.examples.taglib;
+
+import java.util.Locale;
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.jstl.core.LoopTagSupport;
+
+/**
+ * <p>Tag handler for <locales>
+ *
+ * @author Felipe Leme <jstl at felipeal.net>
+ * @version $Revision: 1.3 $ $Date: 2004/02/28 01:01:41 $
+ */
+public class LocalesTag extends LoopTagSupport {
+
+    private static final Locale[] locales = Locale.getAvailableLocales();
+    private int pointer; 
+    private String varTotal;
+
+    public void setVarTotal( String value ) {
+	varTotal = value;
+    }
+
+    public void prepare() {
+	pointer = 0;
+	if ( varTotal!=null && varTotal.length()>0 ) {
+	    pageContext.setAttribute( varTotal, new Integer(locales.length) );
+	}
+    
+    } 
+
+    public boolean hasNext() {
+	return pointer < locales.length;
+    }  
+
+    public Object next() {
+	return locales[ pointer++ ];
+    }
+  
+    public void setBegin( int value ) {
+  	super.begin = value;
+    }
+  
+    public void setEnd( int value ) {
+  	super.end = value;
+    }                     
+}
diff --git a/standard/examples/src/org/apache/taglibs/standard/examples/taglib/NullAttributeException.java b/standard/examples/src/org/apache/taglibs/standard/examples/taglib/NullAttributeException.java
new file mode 100644
index 0000000..9bb9c4d
--- /dev/null
+++ b/standard/examples/src/org/apache/taglibs/standard/examples/taglib/NullAttributeException.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.examples.taglib;
+
+import javax.servlet.jsp.JspTagException;
+
+/**
+ * <p>NullAttributeException is a JspTagException that will be thrown
+ * by the JSTL RI handlers when a tag attribute illegally evaluates
+ * to 'null'.</p>
+ *
+ * @author Shawn Bayern
+ */
+
+public class NullAttributeException extends JspTagException {
+
+    /**
+     * Constructs a ExpressionException with appropriate information.
+     *
+     * @param tag The name of the tag in which the error occurred.
+     * @param att The attribute value for which the error occurred.
+     */
+    public NullAttributeException(String tag, String att) {
+	super("The '" + att + "' attribute illegally evaluated to 'null' "
+	    + "in <" + tag + ">.");
+    }
+}
+
diff --git a/standard/examples/src/org/apache/taglibs/standard/examples/taglib/OddTag.java b/standard/examples/src/org/apache/taglibs/standard/examples/taglib/OddTag.java
new file mode 100644
index 0000000..2d8449d
--- /dev/null
+++ b/standard/examples/src/org/apache/taglibs/standard/examples/taglib/OddTag.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.examples.taglib;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.JspTagException;
+import javax.servlet.jsp.jstl.core.LoopTag;
+import javax.servlet.jsp.tagext.TagSupport;
+
+/**
+ * <p>Tag handler for <odd>
+ *
+ * @author Pierre Delisle
+ * @version $Revision: 1.3 $ $Date: 2004/02/28 01:01:41 $
+ */
+public class OddTag extends TagSupport {
+    
+    //*********************************************************************
+    // TagSupport methods
+    
+    public int doStartTag() throws JspException {
+        LoopTag iteratorTag = (LoopTag)findAncestorWithClass(
+                this, LoopTag.class);
+        if (iteratorTag == null) {
+            throw new JspTagException("<odd> must be nested within a LoopTag");
+        }
+        
+        int count = iteratorTag.getLoopStatus().getCount();
+        System.out.println("count: " + count);
+                System.out.println("count odd/even: " + (count % 2));
+        return (count % 2 == 1) ? EVAL_BODY_INCLUDE : SKIP_BODY;
+    }
+}
+
+
diff --git a/standard/examples/src/org/apache/taglibs/standard/examples/taglib/ResourceTag.java b/standard/examples/src/org/apache/taglibs/standard/examples/taglib/ResourceTag.java
new file mode 100644
index 0000000..ec371b3
--- /dev/null
+++ b/standard/examples/src/org/apache/taglibs/standard/examples/taglib/ResourceTag.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.examples.taglib;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.Reader;
+import java.io.Writer;
+
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletResponseWrapper;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.tagext.TagSupport;
+
+import org.apache.taglibs.standard.examples.util.IOBean;
+import org.apache.taglibs.standard.examples.util.ServletResponseWrapperForWriter;
+
+/**
+ * <p>Tag handler for <resource>
+ *
+ * @author Pierre Delisle
+ * @version $Revision: 1.3 $ $Date: 2004/02/28 01:01:41 $
+ */
+public class ResourceTag extends TagSupport {
+    
+    //*********************************************************************
+    // Instance variables
+    
+    private String id;
+    private String resource;
+    
+    private Reader reader;
+    
+    //*********************************************************************
+    // Constructors
+    
+    public ResourceTag() {
+        super();
+        init();
+    }
+    
+    private void init() {
+        id = null;
+        resource = null;
+    }
+    
+    //*********************************************************************
+    // Tag's properties
+    
+    /**
+     * Tag's 'id' attribute
+     */
+    public void setId(String id) {
+        this.id = id;
+    }
+    
+    /**
+     * Tag's 'resource' attribute
+     */
+    public void setResource(String resource) {
+        this.resource = resource;
+    }
+    
+    //*********************************************************************
+    // TagSupport methods
+    
+    public int doStartTag() throws JspException {
+        reader = getReaderFromResource(resource);
+        exposeVariable(reader);
+        return EVAL_BODY_INCLUDE;
+    }
+    
+    public int doEndTag() throws JspException {
+        try {
+            reader.close();
+        } catch (IOException ex) {}
+        reader = null;
+        return EVAL_PAGE;
+    }
+    
+    /**
+     * Releases any resources we may have (or inherit)
+     */
+    public void release() {
+        super.release();
+        init();
+    }
+    
+    //*********************************************************************
+    // Tag's scific behavior methods
+    
+    private Reader getReaderFromResource(String name) throws JspException {
+        HttpServletRequest request =
+        (HttpServletRequest)pageContext.getRequest();
+        HttpServletResponse response =
+        (HttpServletResponse)pageContext.getResponse();
+        RequestDispatcher rd = null;
+        
+        // The response of the local URL becomes the reader that
+        // we export. Need temporary storage.
+        IOBean ioBean = new IOBean();
+        Writer writer = ioBean.getWriter();
+        ServletResponseWrapper responseWrapper =
+        new ServletResponseWrapperForWriter(
+        response, new PrintWriter(writer));
+        rd = pageContext.getServletContext().getRequestDispatcher(name);
+        try {
+            rd.include(request, responseWrapper);
+            return ioBean.getReader();
+        } catch (Exception ex) {
+            throw new JspException(ex);
+        }
+    }
+    
+    //*********************************************************************
+    // Utility methods
+        
+    private void exposeVariable(Reader reader) {
+        if (id != null) {
+            pageContext.setAttribute(id, reader);
+        }
+    }
+}
diff --git a/standard/examples/src/org/apache/taglibs/standard/examples/taglib/UsCustomerTag.java b/standard/examples/src/org/apache/taglibs/standard/examples/taglib/UsCustomerTag.java
new file mode 100644
index 0000000..f88e0d0
--- /dev/null
+++ b/standard/examples/src/org/apache/taglibs/standard/examples/taglib/UsCustomerTag.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.examples.taglib;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.JspTagException;
+import javax.servlet.jsp.jstl.core.ConditionalTagSupport;
+
+import org.apache.taglibs.standard.examples.beans.Customer;
+
+/**
+ * <p>Tag handler for <usCustomer>
+ *
+ * @author Pierre Delisle
+ * @version $Revision: 1.3 $ $Date: 2004/02/28 01:01:41 $
+ */
+public class UsCustomerTag extends ConditionalTagSupport {
+    
+    //*********************************************************************
+    // Instance Variables
+    
+    /** Holds value of property customer. */
+    private Customer customer;
+    
+    //*********************************************************************
+    // Constructor and lusCustomerecycle management
+    
+    public UsCustomerTag() {
+        super();
+        init();
+    }
+    
+    private void init() {
+        customer = null;
+    }
+    
+    //*********************************************************************
+    // TagSupport methods
+    
+    public void release() {
+        super.release();
+        init();
+    }
+    
+    //*********************************************************************
+    // ConditionalTagSupport methods
+    
+    protected boolean condition() throws JspTagException {
+        try {
+            if (customer == null) {
+                throw new NullAttributeException("usCustomer", "test");
+            } else {
+                //System.out.println("country: " + customer.getAddress().getCountry());
+                return (customer.getAddress().getCountry().equalsIgnoreCase("USA"));
+            }
+        } catch (JspException ex) {
+            throw new JspTagException(ex.toString());
+        }
+    }
+    
+    //*********************************************************************
+    // Accessors
+    
+    /**
+     * Getter for property customer.
+     * @return Value of property customer.
+     */
+    public Customer getCustomer() {
+        return customer;
+    }
+    
+    /**
+     * Setter for property customer.
+     * @param customer New value of property customer.
+     */
+    public void setCustomer(Customer customer) {
+        this.customer = customer;
+    }
+}
diff --git a/standard/examples/src/org/apache/taglibs/standard/examples/util/IOBean.java b/standard/examples/src/org/apache/taglibs/standard/examples/util/IOBean.java
new file mode 100644
index 0000000..adb761d
--- /dev/null
+++ b/standard/examples/src/org/apache/taglibs/standard/examples/util/IOBean.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.examples.util;
+
+import java.io.*;
+import javax.servlet.jsp.JspException;
+
+/**
+ * <p>String repository for Reader/Writer.
+ *
+ * @author Pierre Delisle
+ * @version $Revision: 1.3 $ $Date: 2004/02/28 01:01:41 $
+ */
+public class IOBean {
+    StringWriter stringWriter = null;
+    String content = null;
+
+    public Reader getReader() throws JspException {
+	//p("getReader()");
+	if (content == null) {
+	    if (stringWriter == null) {
+		throw new JspException(
+		    "content must first be added to the bean via the writer");
+	    }
+	    content = stringWriter.toString();
+	}
+	return new StringReader(content);
+    }
+
+    public Writer getWriter() {
+	//p("getWriter()");
+	content = null;
+	stringWriter = new StringWriter();
+	return stringWriter;
+    }
+
+    public void release() {
+	stringWriter = null;
+	content = null;
+    }
+
+    private void p(String s) {
+	System.out.println("[IOBean] " + s);
+    }
+}
diff --git a/standard/examples/src/org/apache/taglibs/standard/examples/util/ServletResponseWrapperForWriter.java b/standard/examples/src/org/apache/taglibs/standard/examples/util/ServletResponseWrapperForWriter.java
new file mode 100644
index 0000000..d173d97
--- /dev/null
+++ b/standard/examples/src/org/apache/taglibs/standard/examples/util/ServletResponseWrapperForWriter.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.examples.util;
+
+import java.io.PrintWriter;
+
+import javax.servlet.*;
+import javax.servlet.http.*;
+import javax.servlet.jsp.*;
+
+/**
+ * ServletResponseWrapper used for the the generation of 
+ * semi-dynamic pages.
+ * <p>
+ * This 'wrapped' response object is passed as the second argument 
+ * to the internal RequestDispatcher.include(). It channels
+ * all output text into the PrintWriter specified in the
+ * constructor (which is associated with the file where the
+ * output of the JSP page has to be saved).
+ *
+ * @author Pierre Delisle
+ * @version $Revision: 1.3 $ $Date: 2004/02/28 01:01:41 $
+ */
+public class ServletResponseWrapperForWriter
+    extends HttpServletResponseWrapper
+{
+    /**
+     * The writer that will get all the output of the response.
+     */
+    PrintWriter writer;
+
+    public ServletResponseWrapperForWriter(ServletResponse response, 
+					   PrintWriter writer) 
+    {
+	super((HttpServletResponse)response);
+	this.writer = writer;
+    }
+
+    /**
+     * Returns the Writer associated with the response.
+     */
+    public java.io.PrintWriter getWriter()
+	throws java.io.IOException 
+    {
+	return writer;
+    }
+}
+
diff --git a/standard/examples/src/org/apache/taglibs/standard/examples/util/Util.java b/standard/examples/src/org/apache/taglibs/standard/examples/util/Util.java
new file mode 100644
index 0000000..5da53f0
--- /dev/null
+++ b/standard/examples/src/org/apache/taglibs/standard/examples/util/Util.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.examples.util;
+
+import java.io.*;
+import javax.servlet.jsp.*;
+
+/**
+ * <p>Utility class for examples webapp.
+ *
+ * @author Pierre Delisle
+ * @version $Revision: 1.3 $ $Date: 2004/02/28 01:01:41 $
+ */
+public class Util {
+
+    public static Writer castToWriter(Object obj) throws JspException {
+        if (obj instanceof OutputStream) {
+            return new OutputStreamWriter((OutputStream)obj);
+        } else if (obj instanceof Writer) {
+            return (Writer)obj;
+            /*@@@
+        } else if (obj instanceof String) {
+            return new StringWriter();
+             */
+        }
+        throw new JspException("Invalid type '" + obj.getClass().getName() +
+			       "' for castToWriter()");
+    }
+    
+    public static Reader castToReader(Object obj) throws JspException {
+        if (obj instanceof InputStream) {
+            return new InputStreamReader((InputStream)obj);
+        } else if (obj instanceof Reader) {
+            return (Reader)obj;
+        } else if (obj instanceof String) {
+            return new StringReader((String)obj);
+        }
+        throw new JspException("Invalid type '" + obj.getClass().getName() +
+			       "' for castToReader()");
+    }
+}
+
diff --git a/standard/examples/web/ShowSource.jsp b/standard/examples/web/ShowSource.jsp
new file mode 100644
index 0000000..9acdff9
--- /dev/null
+++ b/standard/examples/web/ShowSource.jsp
@@ -0,0 +1,36 @@
+<!--
+  Displays the content of the file specified in request
+  parameter "filename".
+  <%-- Warning!  Can be used to retrieve the source code for
+       any file in the 'standard-examples' application.
+       It is not advisable to insert any sensitive code
+       (even as an experiment) into this application --%>
+-->
+
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<%@ taglib prefix="ex" uri="/jstl-examples-taglib" %>
+
+<%-- 
+  Let's get back the URL as a String so we can use it to
+  demonstrate "c:import"
+--%>
+<% pageContext.setAttribute("filepath",
+     application.
+       getResource(request.getParameter("filename")).toExternalForm()); %>
+<% pageContext.setAttribute("filename", request.getParameter("filename")); %>
+
+<html>
+<head>
+  <title>JSTL: Source code for <c:out value="${filename}"/></title>
+</head>
+<body bgcolor="#FFFFFF">
+<h3>Source code for:  ${filename}</h3>
+
+<hr>
+
+<c:import varReader="reader" url="${filepath}">
+  <ex:escapeHtml reader="${reader}"/>
+</c:import>
+<hr>
+</body>
+</html>
diff --git a/standard/examples/web/Templates/ExamplesTemplate.dwt b/standard/examples/web/Templates/ExamplesTemplate.dwt
new file mode 100644
index 0000000..200becc
--- /dev/null
+++ b/standard/examples/web/Templates/ExamplesTemplate.dwt
@@ -0,0 +1,38 @@
+<html>
+<head>
+<!-- #BeginEditable "doctitle" -->
+<title>Untitled Document</title>
+<!-- #EndEditable -->
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<link rel="stylesheet" href="../global.css" type="text/css">
+</head>
+
+<body bgcolor="#FFFFFF" text="#000000">
+<table width="100%" border="0" cellpadding="5">
+  <tr> 
+    <td height="0"><font color="#000099"><b>standard taglib • implementation 
+      of the JSP Standard Tag Library • </b></font><font color="#003399"><a href="mailto:taglibs-user at jakarta.apache.org"><b>support</b></a> 
+        <b><a href="mailto:taglibs-dev at jakarta.apache.org">development</a>   
+      <a href="mailto:jsr-52-comments at jcp.org">comments to JSR-52</a></b></font></td>
+  </tr>
+  <tr> 
+    <td bgcolor="#CCCCFF"><font size="-1">Examples     <a href="../index.html">Introduction</a> 
+      • <a href="../elsupport/index.html">General Purpose</a> • <a href="../conditionals/index.html">Conditionals</a> 
+      • <a href="../iterators/index.html">Iterators</a> • <a href="../import/index.jsp">Import</a> 
+      • <a href="../format/index.html">I18N & Formatting</a> • <a href="../xml/index.html">XML</a> 
+      • <a href="../sql/index.jsp">SQL</a> • <a href="../functions/index.html">Functions</a> 
+      • <a href="../tlv/index.html">TLV</a> • <a href="../misc/index.html"></a><a href="../misc/index.html">Misc.</a></font></td>
+  </tr>
+</table>
+<!-- #BeginEditable "body" -->{body}<!-- #EndEditable -->
+<hr noshade color="#000099">
+<table width="100%" border="0" cellpadding="5">
+  <tr> 
+    <td height="24"><font color="#000099"><b>standard taglib • implementation 
+      of the JSP Standard Tag Library • </b></font><font color="#003399"><a href="mailto:taglibs-user at jakarta.apache.org"><b>support</b></a> 
+        <b><a href="mailto:taglibs-dev at jakarta.apache.org">development</a>   
+      <a href="mailto:jsr-52-comments at jcp.org">comments to JSR-52</a></b></font></td>
+  </tr>
+</table>
+</body>
+</html>
diff --git a/standard/examples/web/WEB-INF/tlds/jstl-examples.tld b/standard/examples/web/WEB-INF/tlds/jstl-examples.tld
new file mode 100644
index 0000000..ef16f9a
--- /dev/null
+++ b/standard/examples/web/WEB-INF/tlds/jstl-examples.tld
@@ -0,0 +1,165 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee web-jsptaglibrary_2_0.xsd"
+    version="2.0">
+  <description>
+    Tag Library to support examples webapp
+  </description>
+  <tlib-version>1.1</tlib-version>
+  <short-name>ex</short-name>
+  <uri>/jstl-examples-taglib</uri>
+
+  <tag>
+    <name>defaultLocale</name>
+    <tag-class>org.apache.taglibs.standard.examples.taglib.DefaultLocaleTag</tag-class>
+    <body-content>JSP</body-content>
+  </tag>
+
+  <tag>
+    <name>locales</name>
+    <tag-class>org.apache.taglibs.standard.examples.taglib.LocalesTag</tag-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <name>var</name>
+        <required>required</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>varStatus</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>varTotal</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>begin</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>end</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <name>escapeHtml</name>
+    <tag-class>org.apache.taglibs.standard.examples.taglib.EscapeHtmlTag</tag-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <name>reader</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>  
+    <attribute>
+        <name>writer</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>  
+  </tag>
+
+  <tag>
+    <name>resource</name>
+    <tag-class>org.apache.taglibs.standard.examples.taglib.ResourceTag</tag-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <name>id</name>
+        <required>true</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>resource</name>
+        <required>true</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>  
+  </tag>
+
+  <tag>
+    <name>file</name>
+    <tag-class>org.apache.taglibs.standard.examples.taglib.FileTag</tag-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <name>id</name>
+        <required>true</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>file</name>
+        <required>true</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>  
+  </tag>
+
+  <tag>
+    <name>odd</name>
+    <tag-class>org.apache.taglibs.standard.examples.taglib.OddTag</tag-class>
+    <body-content>JSP</body-content>
+  </tag>
+
+  <tag>
+    <name>even</name>
+    <tag-class>org.apache.taglibs.standard.examples.taglib.EvenTag</tag-class>
+    <body-content>JSP</body-content>
+  </tag>
+
+  <tag>
+    <name>usCustomer</name>
+    <tag-class>org.apache.taglibs.standard.examples.taglib.UsCustomerTag</tag-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <name>customer</name>
+        <required>true</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>  
+    <attribute>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>  
+  </tag>
+
+  <tag>
+    <name>customerFmt</name>
+    <tag-class>org.apache.taglibs.standard.examples.taglib.CustomerFmtTag</tag-class>
+    <body-content>empty</body-content>
+    <attribute>
+        <name>customer</name>
+        <required>true</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>  
+    <attribute>
+        <name>fmt</name>
+        <required>true</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>  
+  </tag>
+
+  <tag>
+    <name>SPath</name>
+    <tag-class>org.apache.taglibs.standard.extra.spath.SPathTag</tag-class>
+    <body-content>empty</body-content>
+    <attribute>
+        <name>var</name>
+        <required>true</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>  
+    <attribute>
+        <name>select</name>
+        <required>true</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <function>
+    <name>display</name>
+    <function-class>org.apache.taglibs.standard.examples.taglib.Functions</function-class>
+    <function-signature>java.lang.String display(java.lang.Object)</function-signature>
+  </function>
+
+</taglib>
diff --git a/standard/examples/web/WEB-INF/web.xml b/standard/examples/web/WEB-INF/web.xml
new file mode 100644
index 0000000..0bb7db7
--- /dev/null
+++ b/standard/examples/web/WEB-INF/web.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+
+<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee web-app_2_4.xsd"
+    version="2.4">
+
+    <display-name>JSTL Examples</display-name>
+    <description>
+        Examples for the 'standard' taglib (JSTL)
+    </description>
+
+    <listener>
+      <listener-class>org.apache.taglibs.standard.examples.startup.Init</listener-class>
+    </listener>
+
+    <welcome-file-list>
+      <welcome-file>index.jsp</welcome-file>
+      <welcome-file>index.html</welcome-file>
+    </welcome-file-list>
+
+</web-app>
diff --git a/standard/examples/web/conditionals/Choose.jsp b/standard/examples/web/conditionals/Choose.jsp
new file mode 100644
index 0000000..9f7d6d4
--- /dev/null
+++ b/standard/examples/web/conditionals/Choose.jsp
@@ -0,0 +1,27 @@
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+
+<html>
+<head>
+  <title>JSTL: Conditional Support -- Mutually Exclusive Conditional Execution Example</title>
+</head>
+<body bgcolor="#FFFFFF">
+<h3>Mutually Exclusive Conditional Execution</h3>
+
+<h4>USA:blue Canada:red Others:green</h4>
+
+<c:forEach var="customer" items="${customers}">
+  <c:choose>
+    <c:when test="${customer.address.country == 'USA'}">
+      <font color="blue">
+    </c:when>
+    <c:when test="${customer.address.country == 'Canada'}">
+      <font color="red">
+    </c:when>
+    <c:otherwise>
+      <font color="green">	
+    </c:otherwise>	
+  </c:choose>
+  ${customer}</font><br>
+</c:forEach>
+</body>
+</html>
diff --git a/standard/examples/web/conditionals/CustomLogicTag.jsp b/standard/examples/web/conditionals/CustomLogicTag.jsp
new file mode 100644
index 0000000..98de2f7
--- /dev/null
+++ b/standard/examples/web/conditionals/CustomLogicTag.jsp
@@ -0,0 +1,36 @@
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<%@ taglib prefix="ex" uri="/jstl-examples-taglib" %>
+
+<html>
+<head>
+  <title>JSTL: Conditional Support -- Custom Logic Tag Example</title>
+</head>
+<body bgcolor="#FFFFFF">
+
+<h3>Custom Logic Tag</h3>
+
+<h4>Customers living in the USA</h4>
+
+<h4>Simple Conditional Execution</h4>
+<c:forEach var="customer" items="${customers}">
+  <ex:usCustomer customer="${customer}">
+    <c:out value="${customer}"/><br>
+  </ex:usCustomer>
+</c:forEach>
+
+<h4>Mutually Exclusive Conditional Execution</h4>
+
+<c:forEach var="customer" items="${customers}">
+  <ex:usCustomer customer="${customer}" var="isUsCustomer"/>
+  <c:choose>
+    <c:when test="${isUsCustomer}">
+      <font color="blue">
+    </c:when>
+    <c:otherwise>
+      <font color="green">	
+    </c:otherwise>	
+  </c:choose>
+  <c:out value="${customer}"/></font><br>
+</c:forEach>
+</body>
+</html>
diff --git a/standard/examples/web/conditionals/FailureLocal.jsp b/standard/examples/web/conditionals/FailureLocal.jsp
new file mode 100644
index 0000000..fc5d6e1
--- /dev/null
+++ b/standard/examples/web/conditionals/FailureLocal.jsp
@@ -0,0 +1,27 @@
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+
+<html>
+<head>
+  <title>JSTL: Conditional Support -- Mutually Exclusive Conditional Execution Example</title>
+</head>
+<body bgcolor="#FFFFFF">
+<h3>Mutually Exclusive Conditional Execution</h3>
+
+<h4>USA:blue Canada:red Others:green</h4>
+
+<c:forEach var="customer" items="${customers}">
+  <c:choose>
+    <c:otherwise>
+      <font color="green">	
+    </c:otherwise>	
+    <c:when test="${customer.address.country == 'USA'}">
+      <font color="blue">
+    </c:when>
+    <c:when test="${customer.address.country == 'Canada'}">
+      <font color="red">
+    </c:when>
+  </c:choose>
+  <c:out value="${customer}"/></font><br>
+</c:forEach>
+</body>
+</html>
diff --git a/standard/examples/web/conditionals/If.jsp b/standard/examples/web/conditionals/If.jsp
new file mode 100644
index 0000000..8b33c2d
--- /dev/null
+++ b/standard/examples/web/conditionals/If.jsp
@@ -0,0 +1,19 @@
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+
+<html>
+<head>
+  <title>JSTL: Conditional Support -- Simple Conditional Execution Example</title>
+</head>
+<body bgcolor="#FFFFFF">
+
+<h3>Simple Conditional Execution</h3>
+
+<h4>Customers living in the USA</h4>
+
+<c:forEach var="customer" items="${customers}">
+  <c:if test="${customer.address.country == 'USA'}">
+    ${customer}<br>
+  </c:if>
+</c:forEach>
+</body>
+</html>
diff --git a/standard/examples/web/conditionals/index.html b/standard/examples/web/conditionals/index.html
new file mode 100644
index 0000000..5ae33e1
--- /dev/null
+++ b/standard/examples/web/conditionals/index.html
@@ -0,0 +1,59 @@
+<html><!-- #BeginTemplate "/Templates/ExamplesTemplate.dwt" -->
+<head>
+<!-- #BeginEditable "doctitle" --> 
+<title>JSTL: Conditional Tags Examples</title>
+<!-- #EndEditable -->
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<link rel="stylesheet" href="../global.css" type="text/css">
+</head>
+
+<body bgcolor="#FFFFFF" text="#000000">
+<table width="100%" border="0" cellpadding="5">
+  <tr> 
+    <td height="0"><font color="#000099"><b>standard taglib • implementation 
+      of the JSP Standard Tag Library • </b></font><font color="#003399"><a href="mailto:taglibs-user at jakarta.apache.org"><b>support</b></a> 
+        <b><a href="mailto:taglibs-dev at jakarta.apache.org">development</a>   
+      <a href="mailto:jsr-52-comments at jcp.org">comments to JSR-52</a></b></font></td>
+  </tr>
+  <tr> 
+    <td bgcolor="#CCCCFF"><font size="-1">Examples     <a href="../index.html">Introduction</a> 
+      • <a href="../elsupport/index.html">General Purpose</a> 
+      • <a href="index.html">Conditionals</a> 
+      • <a href="../iterators/index.html">Iterators</a> • 
+      <a href="../import/index.jsp">Import</a> • <a href="../format/index.html">I18N 
+      & Formatting</a> • <a href="../xml/index.html">XML</a> 
+      • <a href="../sql/index.jsp">SQL</a> • <a href="../functions/index.html">Functions</a> 
+      • <a href="../tlv/index.html">TLV</a> • <a href="../functions/index.html"></a><a href="../misc/index.html">Misc.</a></font></td>
+  </tr>
+</table>
+<!-- #BeginEditable "body" --> 
+<h2>Conditional Tags Examples</h2>
+<h3><if> Simple Conditional Execution   <a href="../ShowSource.jsp?filename=/conditionals/If.jsp"><img src="../images/code.gif" width="24" height="24" border="0"></a> 
+  <a href="If.jsp"><img src="../images/execute.gif" width="24" height="24" border="0"></a> 
+</h3>
+Only shows a customer from the customer list if they are living in the "USA".<br>
+<h3> <choose> Mutually Exclusive Conditional Execution <a href="../ShowSource.jsp?filename=/conditionals/Choose.jsp"><img src="../images/code.gif" width="24" height="24"" border="0"></a> 
+  <a href="Choose.jsp"><img src="../images/execute.gif" width="24" height="24" border="0"></a> 
+</h3>
+<p>Customers from the USA will be printed in blue, those from Canada in red, and 
+  others in green.</p>
+<h3>Custom Logic Tag  <a href="../ShowSource.jsp?filename=/conditionals/CustomLogicTag.jsp"><img src="../images/code.gif" width="24" height="24" border="0"></a> <a href="CustomLogicTag.jsp"><img src="../images/execute.gif" width="24" height="24" border="0"></a></h3>
+<p>JSTL exposes in its API the abstract class ConditionalTagSupport to facilitate 
+  the implementation of custom conditional tags that leverage the standard conditional 
+  behavior defined in JSTL. This example shows custom tag <usCustomer> that 
+  returns true if its customer attribute value points to a US customer. It can 
+  be used both in the context of a simple conditional execution, as well as in 
+  the context of a mutually conditional execution by exposing the result of the 
+  conditional execution in a JSP page attribute via the tag attribute 'var'. </p>
+<!-- #EndEditable -->
+<hr noshade color="#000099">
+<table width="100%" border="0" cellpadding="5">
+  <tr> 
+    <td height="24"><font color="#000099"><b>standard taglib • implementation 
+      of the JSP Standard Tag Library • </b></font><font color="#003399"><a href="mailto:taglibs-user at jakarta.apache.org"><b>support</b></a> 
+        <b><a href="mailto:taglibs-dev at jakarta.apache.org">development</a>   
+      <a href="mailto:jsr-52-comments at jcp.org">comments to JSR-52</a></b></font></td>
+  </tr>
+</table>
+</body>
+<!-- #EndTemplate --></html>
diff --git a/standard/examples/web/elsupport/Out.jsp b/standard/examples/web/elsupport/Out.jsp
new file mode 100644
index 0000000..b474a48
--- /dev/null
+++ b/standard/examples/web/elsupport/Out.jsp
@@ -0,0 +1,34 @@
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<html>
+<head>
+  <title>JSTL: Expression Language Support -- Expr Example</title>
+</head>
+<body bgcolor="#FFFFFF">
+
+<h3><c:out></h3>
+
+<table border="1">
+  <c:forEach var="customer" items="${customers}">
+    <tr>
+      <td><c:out value="${customer.lastName}"/></td>
+      <td><c:out value="${customer.phoneHome}" default="no home phone specified"/></td>
+      <td>
+        <c:out value="${customer.phoneCell}" escapeXml="false">
+          <font color="red">no cell phone specified</font>
+        </c:out>
+      </td>
+    </tr>
+  </c:forEach>
+</table>
+
+<h4><c:out> with Reader object</h4>
+<%
+java.io.Reader reader1 = new java.io.StringReader("<foo>Text for a Reader!</foo>");
+pageContext.setAttribute("myReader1", reader1);
+java.io.Reader reader2 = new java.io.StringReader("<foo>Text for a Reader!</foo>");
+pageContext.setAttribute("myReader2", reader2);
+%>
+Reader1 (escapeXml=true) : <c:out value="${myReader1}"/><br>
+Reader2 (escapeXml=false): <c:out value="${myReader2}" escapeXml="false"/><br>
+</body>
+</html>
diff --git a/standard/examples/web/elsupport/Set.jsp b/standard/examples/web/elsupport/Set.jsp
new file mode 100644
index 0000000..06de847
--- /dev/null
+++ b/standard/examples/web/elsupport/Set.jsp
@@ -0,0 +1,33 @@
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+
+<html>
+<head>
+  <title>JSTL: Expression Language Support -- Set Example</title>
+</head>
+<body bgcolor="#FFFFFF">
+<h3><c:set></h3>
+
+<h4>Setting application scope attribute "customerTable"</h4>
+
+<c:set var="customerTable" scope="application">
+<table border="1">
+    <c:forEach var="customer" items="${customers}">
+    <tr>
+	  <td>${customer.lastName}</td>
+	  <td><c:out value="${customer.address}" default="no address specified"/></td>
+	  <td>
+	    <c:out value="${customer.address}">
+		  <font color="red">no address specified</font>
+		</c:out>
+      </td>
+	</tr>
+  </c:forEach>
+</table>
+</c:set>
+
+<p> 
+Using customerTable in another JSP page 
+<a href="../ShowSource.jsp?filename=/elsupport/Set2.jsp"><img src="../images/code.gif" width="24" height="24" border="0"></a> 
+<a href="../elsupport/Set2.jsp"><img src="../images/execute.gif" width="24" height="24" border="0"></a> 
+</body>
+</html>
diff --git a/standard/examples/web/elsupport/Set2.jsp b/standard/examples/web/elsupport/Set2.jsp
new file mode 100644
index 0000000..20a777f
--- /dev/null
+++ b/standard/examples/web/elsupport/Set2.jsp
@@ -0,0 +1,16 @@
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<html>
+<head>
+  <title>JSTL: Expression Language Support -- Set 2 Example</title>
+</head>
+<body bgcolor="#FFFFFF">
+
+<h3><c:set></h3>
+
+<h4>Using "customerTable" application scope attribute defined in Set.jsp a first time</h4>
+<c:out value="${customerTable}" escapeXml="false"/>
+
+<h4>Using "customerTable" application scope attribute defined in Set.jsp a second time</h4>
+<c:out value="${customerTable}" escapeXml="false" />
+</body>
+</html>
diff --git a/standard/examples/web/elsupport/index.html b/standard/examples/web/elsupport/index.html
new file mode 100644
index 0000000..25c2a0e
--- /dev/null
+++ b/standard/examples/web/elsupport/index.html
@@ -0,0 +1,60 @@
+<html><!-- #BeginTemplate "/Templates/ExamplesTemplate.dwt" -->
+<head>
+<!-- #BeginEditable "doctitle" --> 
+<title>JSTL: General-Purpose Tags Examples</title>
+<!-- #EndEditable -->
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<link rel="stylesheet" href="../global.css" type="text/css">
+</head>
+
+<body bgcolor="#FFFFFF" text="#000000">
+<table width="100%" border="0" cellpadding="5">
+  <tr> 
+    <td height="0"><font color="#000099"><b>standard taglib • implementation 
+      of the JSP Standard Tag Library • </b></font><font color="#003399"><a href="mailto:taglibs-user at jakarta.apache.org"><b>support</b></a> 
+        <b><a href="mailto:taglibs-dev at jakarta.apache.org">development</a>   
+      <a href="mailto:jsr-52-comments at jcp.org">comments to JSR-52</a></b></font></td>
+  </tr>
+  <tr> 
+    <td bgcolor="#CCCCFF"><font size="-1">Examples     <a href="../index.html">Introduction</a> 
+      • <a href="index.html">General Purpose</a> 
+      • <a href="../conditionals/index.html">Conditionals</a> 
+      • <a href="../iterators/index.html">Iterators</a> • 
+      <a href="../import/index.jsp">Import</a> • <a href="../format/index.html">I18N 
+      & Formatting</a> • <a href="../xml/index.html">XML</a> 
+      • <a href="../sql/index.jsp">SQL</a> • <a href="../functions/index.html">Functions</a> 
+      • <a href="../tlv/index.html">TLV</a> • <a href="../functions/index.html"></a><a href="../misc/index.html">Misc.</a></font></td>
+  </tr>
+</table>
+<!-- #BeginEditable "body" --> 
+<h2>General-Purpose Tags Examples</h2>
+<h3><out>   <a href="../ShowSource.jsp?filename=/elsupport/Out.jsp"><img src="../images/code.gif" width="24" height="24" border="0"></a> 
+  <a href="../elsupport/Out.jsp"><img src="../images/execute.gif" width="24" height="24" border="0"></a> 
+</h3>
+This example features <out> used with default values using the default attribute 
+as well as the tag's body content. <br>
+<h3> <set>  <a href="../ShowSource.jsp?filename=/elsupport/Set.jsp"><img src="../images/code.gif" width="24" height="24" border="0"></a> 
+  <a href="../elsupport/Set.jsp"><img src="../images/execute.gif" width="24" height="24" border="0"></a></h3>
+<p>We set the value of an application scope attribute from the <set> tag 
+  body content. This application scope variable is then used in a second JSP page.</p>
+<!--
+<h3><declare>  <a href="../ShowSource.jsp?filename=/elsupport/Declare.jsp"><img src="../images/code.gif" width="24" height="24" border="0"></a> 
+  <a href="../elsupport/Declare.jsp"><img src="../images/execute.gif" width="24" height="24" border="0"></a></h3>
+<p>In order for JSTL tags to collaborate with custom tags that only accept rtexprvalues, 
+  the <declare> tag must be used to create a scripting variable. In this 
+  example, the page attribute created by the <forEach> tag is used in the 
+  <declare> tag to export a scripting variable that is then used in custom 
+  tag <customerFmt>.</p>
+-->
+<!-- #EndEditable -->
+<hr noshade color="#000099">
+<table width="100%" border="0" cellpadding="5">
+  <tr> 
+    <td height="24"><font color="#000099"><b>standard taglib • implementation 
+      of the JSP Standard Tag Library • </b></font><font color="#003399"><a href="mailto:taglibs-user at jakarta.apache.org"><b>support</b></a> 
+        <b><a href="mailto:taglibs-dev at jakarta.apache.org">development</a>   
+      <a href="mailto:jsr-52-comments at jcp.org">comments to JSR-52</a></b></font></td>
+  </tr>
+</table>
+</body>
+<!-- #EndTemplate --></html>
diff --git a/standard/examples/web/format/Demo.jsp b/standard/examples/web/format/Demo.jsp
new file mode 100644
index 0000000..7daf396
--- /dev/null
+++ b/standard/examples/web/format/Demo.jsp
@@ -0,0 +1,118 @@
+<%@ page import="javax.servlet.jsp.jstl.core.Config, java.util.*" %>
+
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
+
+<html>
+<head>
+  <title>JSTL: Formatting/I18N Support -- Demo Example</title>
+</head>
+<body bgcolor="#FFFFFF">
+
+<h3>Demo</h3>
+<p>
+The following bundles exist in the web application: 'Resources', 'Resources_de', 'Resources_fr', 'Resources_it'. 
+'Resources' is the 'base' bundle and contains all messages in English. The italian bundle only holds one message
+(key=greetingMorning).
+</p>
+<c:if test="${!empty param.locale}">
+  <fmt:setLocale value="${param.locale}" scope="page"/>
+</c:if>
+
+<c:if test="${!empty param.fallback}">
+  <% Config.set(request, Config.FMT_FALLBACK_LOCALE, request.getParameter("fallback")); %>
+</c:if>
+
+<table>
+<tr>
+  <td><b>Set application-based locale:</b></td>
+  <td>
+<a href='?locale=fr&fallback=<c:out value="${param.fallback}"/>'>French</a> •
+<a href='?locale=de&fallback=<c:out value="${param.fallback}"/>'>German</a> •
+<a href='?locale=it&fallback=<c:out value="${param.fallback}"/>'>Italian</a> •
+<a href='?locale=es&fallback=<c:out value="${param.fallback}"/>'>Spanish (no bundle)</a> •
+<a href='?locale=&fallback=<c:out value="${param.fallback}"/>'>None</a>
+  </td>
+</tr>
+<tr>
+  <td align="right"><b>Set fallback locale:</b></td>
+  <td>
+<a href='?locale=<c:out value="${param.locale}"/>&fallback=fr'>French</a> •
+<a href='?locale=<c:out value="${param.locale}"/>&fallback=de'>German</a> •
+<a href='?locale=<c:out value="${param.locale}"/>&fallback=it'>Italian</a> •
+<a href='?locale=<c:out value="${param.locale}"/>&fallback=es'>Spanish (no bundle)</a> •
+<a href='?locale=<c:out value="${param.locale}"/>&fallback='>None</a>
+  </td>
+</table>
+<p>
+
+Request parameter "locale": <c:out value="${param.locale}"/><br>
+<i>(This value is used to set the application based locale for this example)</i>
+<p>
+
+Application based locale: <%=Config.find(pageContext, Config.FMT_LOCALE)%><br>
+<i>(javax.servlet.jsp.jstl.fmt.locale configuration setting)</i>
+<p>
+
+Browser-Based locales: 
+<% 
+  Enumeration enum_ = request.getLocales();
+  while (enum_.hasMoreElements()) {
+    Locale locale = (Locale)enum_.nextElement();
+    out.print(locale);
+    out.print(" ");
+  }
+%>
+<br>
+<i>(ServletRequest.getLocales() on the incoming request)</i>
+<p>
+
+Fallback locale: <%=Config.find(pageContext, Config.FMT_FALLBACK_LOCALE)%><br>
+<i>(javax.servlet.jsp.jstl.fmt.fallbackLocale configuration setting)</i>
+<p>
+
+<jsp:useBean id="now" class="java.util.Date" />
+<h4>
+<fmt:formatDate value="${now}" dateStyle="full"/> •
+<fmt:formatDate value="${now}" type="time"/>
+</h4>
+
+<p>
+
+<fmt:bundle basename="org.apache.taglibs.standard.examples.i18n.Resources">
+<table cellpadding="5" border="1">
+  <tr>
+    <th align="left">KEY</th>
+    <th align="left">VALUE</th>
+  </tr>
+  <tr>
+    <td>greetingMorning</td>
+    <td><fmt:message key="greetingMorning"/></td>
+  </tr>
+  <tr>
+    <td>greetingEvening</td>
+    <td><fmt:message key="greetingEvening"/></td>
+  </tr>
+  <tr>
+    <td>currentTime</td>
+    <td>
+      <fmt:message key="currentTime">
+        <fmt:param value="${now}"/>
+      </fmt:message>
+    </td>
+  </tr>
+  <tr>
+    <td>serverInfo</td>
+    <td><fmt:message key="serverInfo"/></td>
+  </tr>
+  <tr>
+    <td>undefinedKey</td>
+    <td><fmt:message key="undefinedKey"/></td>
+  </tr>
+</table>
+</fmt:bundle>
+
+<p>
+
+</body>
+</html>
diff --git a/standard/examples/web/format/FormatDateTime.jsp b/standard/examples/web/format/FormatDateTime.jsp
new file mode 100644
index 0000000..33a7e56
--- /dev/null
+++ b/standard/examples/web/format/FormatDateTime.jsp
@@ -0,0 +1,74 @@
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
+
+<html>
+<head>
+  <title>JSTL: Formatting/I18N Support -- Date and Time Example</title>
+</head>
+<body bgcolor="#FFFFFF">
+<h3>Formatting dates and times using <tt>en-US</tt> locale</h3>
+
+<jsp:useBean id="now" class="java.util.Date" />
+<fmt:setLocale value="en-US" />
+
+<ul>
+ <li> Formatting current date as "GMT":<br>
+  <fmt:timeZone value="GMT">
+   <fmt:formatDate value="${now}" type="both" dateStyle="full"
+                   timeStyle="full"/>
+  </fmt:timeZone>
+
+ <li> Formatting current date as "GMT+1:00", and parsing
+      its date and time components:<br>
+  <fmt:timeZone value="GMT+1:00">
+   <fmt:formatDate value="${now}" type="both" dateStyle="full"
+                   timeStyle="full" var="formatted"/>
+   <fmt:parseDate value="${formatted}" type="both" dateStyle="full"
+                  timeStyle="full" timeZone="PST" var="parsedDateTime"/>
+   Parsed date: <fmt:formatDate value="${parsedDateTime}" type="date"
+                                dateStyle="full"/><br>
+   Parsed time: <fmt:formatDate value="${parsedDateTime}" type="time"
+                                timeStyle="full"/>
+  </fmt:timeZone>
+
+ <li> Parsing SHORT version of current time in different time zones:<br>
+  <fmt:formatDate value="${now}" type="both" timeStyle="short"
+                  var="formatted"/>
+  <fmt:parseDate value="${formatted}" type="both" timeStyle="short"
+                 timeZone="GMT" var="parsed"/>
+  <c:out value="${parsed}"/> (parsed in "GMT")<br>
+
+  <fmt:parseDate value="${formatted}" type="both" timeStyle="short"
+                 timeZone="GMT+1:00" var="parsed"/>
+  <c:out value="${parsed}"/> (parsed in "GMT+1:00")<br>
+
+  <fmt:parseDate value="${formatted}" type="both" timeStyle="short"
+                 timeZone="GMT+3:00" var="parsed"/>
+  <c:out value="${parsed}"/> (parsed in "GMT+3:00")<br>
+
+  <fmt:parseDate value="${formatted}" type="both" timeStyle="short"
+                 timeZone="PST" var="parsed"/>
+  <c:out value="${parsed}"/> (parsed in "PST")
+
+ <li> Parsing FULL version of current time in different time zones<br>
+      (parse result is independent of specified time zone):<br>
+  <fmt:formatDate value="${now}" type="both" timeStyle="full" var="formatted"/>
+  <fmt:parseDate value="${formatted}" type="both" timeStyle="full"
+                 timeZone="GMT" var="parsed"/>
+  <c:out value="${parsed}"/> (parsed in "GMT")<br>
+
+  <fmt:parseDate value="${formatted}" type="both" timeStyle="full"
+                 timeZone="GMT+1:00" var="parsed"/>
+  <c:out value="${parsed}"/> (parsed in "GMT+1:00")<br>
+
+  <fmt:parseDate value="${formatted}" type="both" timeStyle="full"
+                 timeZone="GMT+3:00" var="parsed"/>
+  <c:out value="${parsed}"/> (parsed in "GMT+3:00")<br>
+
+  <fmt:parseDate value="${formatted}" type="both" timeStyle="full"
+                 timeZone="PST" var="parsed"/>
+  <c:out value="${parsed}"/> (parsed in "PST")
+</ul>
+
+</body>
+</html>
diff --git a/standard/examples/web/format/FormatDateTimeBrowserLocale.jsp b/standard/examples/web/format/FormatDateTimeBrowserLocale.jsp
new file mode 100644
index 0000000..01340d3
--- /dev/null
+++ b/standard/examples/web/format/FormatDateTimeBrowserLocale.jsp
@@ -0,0 +1,73 @@
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
+
+<html>
+<head>
+  <title>JSTL: Formatting/I18N Support -- Date and Time Example</title>
+</head>
+<body bgcolor="#FFFFFF">
+<h3>Formatting dates and times using browser-based locale</h3>
+
+<jsp:useBean id="now" class="java.util.Date" />
+
+<ul>
+ <li> Formatting current date as "GMT":<br>
+  <fmt:timeZone value="GMT">
+   <fmt:formatDate value="${now}" type="both" dateStyle="full"
+                   timeStyle="full"/>
+  </fmt:timeZone>
+
+ <li> Formatting current date as "GMT+1:00", and parsing
+      its date and time components:<br>
+  <fmt:timeZone value="GMT+1:00">
+   <fmt:formatDate value="${now}" type="both" dateStyle="full"
+                   timeStyle="full" var="formatted"/>
+   <fmt:parseDate value="${formatted}" type="both" dateStyle="full"
+                  timeStyle="full" timeZone="PST" var="parsedDateTime"/>
+   Parsed date: <fmt:formatDate value="${parsedDateTime}" type="date"
+                                dateStyle="full"/><br>
+   Parsed time: <fmt:formatDate value="${parsedDateTime}" type="time"
+                                timeStyle="full"/>
+  </fmt:timeZone>
+
+ <li> Parsing SHORT version of current time in different time zones:<br>
+  <fmt:formatDate value="${now}" type="both" timeStyle="short"
+                  var="formatted"/>
+  <fmt:parseDate value="${formatted}" type="both" timeStyle="short"
+                 timeZone="GMT" var="parsed"/>
+  <c:out value="${parsed}"/> (parsed in "GMT")<br>
+
+  <fmt:parseDate value="${formatted}" type="both" timeStyle="short"
+                 timeZone="GMT+1:00" var="parsed"/>
+  <c:out value="${parsed}"/> (parsed in "GMT+1:00")<br>
+
+  <fmt:parseDate value="${formatted}" type="both" timeStyle="short"
+                 timeZone="GMT+3:00" var="parsed"/>
+  <c:out value="${parsed}"/> (parsed in "GMT+3:00")<br>
+
+  <fmt:parseDate value="${formatted}" type="both" timeStyle="short"
+                 timeZone="PST" var="parsed"/>
+  <c:out value="${parsed}"/> (parsed in "PST")
+
+ <li> Parsing FULL version of current time in different time zones<br>
+      (parse result is independent of specified time zone):<br>
+  <fmt:formatDate value="${now}" type="both" timeStyle="full" var="formatted"/>
+  <fmt:parseDate value="${formatted}" type="both" timeStyle="full"
+                 timeZone="GMT" var="parsed"/>
+  <c:out value="${parsed}"/> (parsed in "GMT")<br>
+
+  <fmt:parseDate value="${formatted}" type="both" timeStyle="full"
+                 timeZone="GMT+1:00" var="parsed"/>
+  <c:out value="${parsed}"/> (parsed in "GMT+1:00")<br>
+
+  <fmt:parseDate value="${formatted}" type="both" timeStyle="full"
+                 timeZone="GMT+3:00" var="parsed"/>
+  <c:out value="${parsed}"/> (parsed in "GMT+3:00")<br>
+
+  <fmt:parseDate value="${formatted}" type="both" timeStyle="full"
+                 timeZone="PST" var="parsed"/>
+  <c:out value="${parsed}"/> (parsed in "PST")
+</ul>
+
+</body>
+</html>
diff --git a/standard/examples/web/format/FormatNumber.jsp b/standard/examples/web/format/FormatNumber.jsp
new file mode 100644
index 0000000..2c1d5ce
--- /dev/null
+++ b/standard/examples/web/format/FormatNumber.jsp
@@ -0,0 +1,41 @@
+<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
+
+<html>
+<head>
+ <title>JSTL: Formatting/I18N Support -- Number, Currency, and Percent
+        Example
+ </title>
+</head>
+<body bgcolor="#FFFFFF">
+<h3>Formatting numbers, currencies, and percentages using <tt>en-US</tt>
+    locale
+</h3>
+
+<fmt:setLocale value="en-US" />
+
+<ul>
+ <li> Format "123456789" as number:<br>
+  <fmt:formatNumber value="123456789" />
+
+ <li> Format "123456789" as percent:<br>
+  <fmt:formatNumber type="percent">123456789</fmt:formatNumber>
+
+ <li> Format "12345.67" as currency:<br>
+  <fmt:formatNumber value="12345.67" type="currency" />
+
+ <li> Format "12345.67" as currency, with
+      grouping turned off, the maximum number of digits in the integer portion
+      limited to 4, and no fraction portion:<br>
+  <fmt:formatNumber value="12345.67" type="currency"
+                    groupingUsed="false" maxIntegerDigits="4"
+                    maxFractionDigits="0" />
+
+ <li> Format "12345.67" as currency:<br>
+  <fmt:formatNumber value="12345.67" type="currency" /><br>
+      then parse its integer portion only and output the result:<br>
+  <fmt:formatNumber value="12345.67" type="currency" var="cur" />
+  <fmt:parseNumber value="${cur}" type="currency" integerOnly="true" />
+</ul>
+
+</body>
+</html>
diff --git a/standard/examples/web/format/FormatNumberBrowserLocale.jsp b/standard/examples/web/format/FormatNumberBrowserLocale.jsp
new file mode 100644
index 0000000..81c0ca4
--- /dev/null
+++ b/standard/examples/web/format/FormatNumberBrowserLocale.jsp
@@ -0,0 +1,52 @@
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
+
+<html>
+<head>
+ <title>JSTL: Formatting/I18N Support -- Number, Currency, and Percent
+        Example
+ </title>
+</head>
+<body bgcolor="#FFFFFF">
+<h3>Formatting numbers, currencies, and percentages using browser-based
+    locale
+</h3>
+
+<c:catch var="ex">
+<ul>
+ <li> Format "123456789" as number:<br>
+  <fmt:formatNumber value="123456789" />
+
+ <li> Format "123456789" as percent:<br>
+  <fmt:formatNumber type="percent">123456789</fmt:formatNumber>
+
+ <li> Format "12345.67" as currency:<br>
+  <fmt:formatNumber value="12345.67" type="currency" />
+
+ <li> Format "12345.67" as currency, with
+      grouping turned off, the maximum number of digits in the integer portion
+      limited to 4, and no fraction portion:<br>
+  <fmt:formatNumber value="12345.67" type="currency"
+                    groupingUsed="false" maxIntegerDigits="4"
+                    maxFractionDigits="0" />
+
+ <li> Format "12345.67" as currency:<br>
+  <fmt:formatNumber value="12345.67" type="currency" /><br>
+      then parse its integer portion only and output the result:<br>
+  <fmt:formatNumber value="12345.67" type="currency" var="cur" />
+  <fmt:parseNumber value="${cur}" type="currency" integerOnly="true" />
+</ul>
+</c:catch>
+
+<c:if test="${not empty ex}">
+  <font color="#FF0000">
+    <br> The following error has occurred:<br><br>
+    <c:out value="${ex}" escapeXml='false'/> <br>
+    <c:if test="${ex.rootCause.class.name == 'java.text.ParseException' && pageContext.response.locale == 'de_DE'}">
+      <br> This is due to a known bug in java.text.NumberFormat (Bugtraq bugid: 4709840).
+    </c:if>
+  </font>
+</c:if>
+
+</body>
+</html>
diff --git a/standard/examples/web/format/GermanLocale.jsp b/standard/examples/web/format/GermanLocale.jsp
new file mode 100644
index 0000000..553705a
--- /dev/null
+++ b/standard/examples/web/format/GermanLocale.jsp
@@ -0,0 +1,18 @@
+<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
+
+<html>
+<head>
+  <title>JSTL: Formatting/I18N Support -- German Locale Example</title>
+</head>
+<body bgcolor="#FFFFFF">
+<h3>German Locale</h3>
+
+<fmt:setLocale value="de"/>
+<fmt:bundle basename="org.apache.taglibs.standard.examples.i18n.Resources">
+ <fmt:message>
+  greetingMorning
+ </fmt:message>
+</fmt:bundle>
+
+</body>
+</html>
diff --git a/standard/examples/web/format/GermanUmlautCorrect.jsp b/standard/examples/web/format/GermanUmlautCorrect.jsp
new file mode 100644
index 0000000..0ae0103
--- /dev/null
+++ b/standard/examples/web/format/GermanUmlautCorrect.jsp
@@ -0,0 +1,20 @@
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
+
+<html>
+<head>
+  <title>JSTL: Formatting/I18N Support -- Request Encoding Example</title>
+</head>
+<body bgcolor="#FFFFFF">
+<h3>German Umlaut characters decoded correctly:</h3>
+
+<fmt:requestEncoding value="UTF-8"/>
+
+<ul>
+ <li>a umlaut: <c:out value="${param.a_umlaut}"/>
+ <li>o umlaut: <c:out value="${param.o_umlaut}"/>
+ <li>u umlaut: <c:out value="${param.u_umlaut}"/>
+</ul>
+
+</body>
+</html>
diff --git a/standard/examples/web/format/GermanUmlautIncorrect.jsp b/standard/examples/web/format/GermanUmlautIncorrect.jsp
new file mode 100644
index 0000000..fb58917
--- /dev/null
+++ b/standard/examples/web/format/GermanUmlautIncorrect.jsp
@@ -0,0 +1,18 @@
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
+
+<html>
+<head>
+  <title>JSTL: Formatting/I18N Support -- Request Encoding Example</title>
+</head>
+<body bgcolor="#FFFFFF">
+<h3>German Umlaut characters decoded incorrectly:</h3>
+
+<ul>
+ <li>a umlaut: <c:out value="${param.a_umlaut}"/>
+ <li>o umlaut: <c:out value="${param.o_umlaut}"/>
+ <li>u umlaut: <c:out value="${param.u_umlaut}"/>
+</ul>
+
+</body>
+</html>
diff --git a/standard/examples/web/format/ItalianLocale.jsp b/standard/examples/web/format/ItalianLocale.jsp
new file mode 100644
index 0000000..44095bd
--- /dev/null
+++ b/standard/examples/web/format/ItalianLocale.jsp
@@ -0,0 +1,15 @@
+<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
+
+<html>
+<head>
+  <title>JSTL: Formatting/I18N Support -- Italian Locale Example</title>
+</head>
+<body bgcolor="#FFFFFF">
+<h3>Italian Locale</h3>
+
+<fmt:setLocale value="it_IT"/>
+<fmt:setBundle basename="org.apache.taglibs.standard.examples.i18n.Resources" var="itBundle" scope="page"/>
+<fmt:message key="greetingMorning" bundle="${itBundle}"/>
+
+</body>
+</html>
diff --git a/standard/examples/web/format/MissingResourceBundle.jsp b/standard/examples/web/format/MissingResourceBundle.jsp
new file mode 100644
index 0000000..1f05a13
--- /dev/null
+++ b/standard/examples/web/format/MissingResourceBundle.jsp
@@ -0,0 +1,22 @@
+<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
+
+<html>
+<head>
+  <title>JSTL: Formatting/I18N Support -- Missing Resource Bundle Example</title>
+</head>
+<body bgcolor="#FFFFFF">
+<h3>Missing Resource Bundle</h3>
+
+<ul>
+ <li> Implicit collaboration with <bundle> (via ancestry chain):<br>
+  <fmt:bundle basename="org.apache.taglibs.standard.examples.i18n.MissingResources">
+   <fmt:message key="greetingMorning"/>
+  </fmt:bundle>
+
+ <li> Explicit collaboration with <bundle> (via <tt>var</tt> attribute):<br>
+  <fmt:setBundle basename="org.apache.taglibs.standard.examples.i18n.MissingResources" var="enBundle"/>
+  <fmt:message key="greetingEvening" bundle="${enBundle}"/>
+</ul>
+
+</body>
+</html>
diff --git a/standard/examples/web/format/ParametricReplacement.jsp b/standard/examples/web/format/ParametricReplacement.jsp
new file mode 100644
index 0000000..d8cd75a
--- /dev/null
+++ b/standard/examples/web/format/ParametricReplacement.jsp
@@ -0,0 +1,66 @@
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
+
+<html>
+<head>
+  <title>JSTL: Formatting/I18N Support -- Parametric Replacement Example</title>
+</head>
+<body bgcolor="#FFFFFF">
+<h3>Parametric Replacement</h3>
+
+<jsp:useBean id="now" class="java.util.Date" />
+
+<fmt:setLocale value="de"/>
+<fmt:setBundle basename="org.apache.taglibs.standard.examples.i18n.Resources" var="deBundle"/>
+
+<fmt:formatDate value="${now}" type="both" var="currentDateString"/>
+<fmt:parseDate value="${currentDateString}" type="both" var="currentDate"/>
+
+<ul>
+ <li> Using single <param> with 'value' evaluating to String:<br>
+  <fmt:message key="currentTime" bundle="${deBundle}">
+   <fmt:param value="${currentDateString}"/>
+  </fmt:message>
+ 
+ <li> Using single <param> with 'value' evaluating to <tt>java.util.Date</tt>:<br>
+  <fmt:message key="currentTime" bundle="${deBundle}">
+   <fmt:param value="${currentDate}"/>
+  </fmt:message>
+
+ <li> Using single <param> with body:<br>
+  <fmt:message key="currentTime" bundle="${deBundle}">
+   <fmt:param>
+    <fmt:formatDate value="${now}" type="both"/>
+   </fmt:param>
+  </fmt:message>
+
+ <li> Using multiple parameters:<br>
+  <fmt:message key="serverInfo" bundle="${deBundle}">
+   <c:forEach var="arg" items="${serverInfoArgs}">
+    <fmt:param value="${arg}"/>
+   </c:forEach>
+  </fmt:message>
+</ul>
+
+<ul>
+ <fmt:setLocale value="es"/>
+ <fmt:setBundle basename="org.apache.taglibs.standard.examples.i18n.Resources" var="esBundle"/>
+ <li>Locale set to Spanish yields a locale-less localization context. Formatting still done
+     using the preferred locale:<br>
+  <fmt:message key="currentTime" bundle="${esBundle}">
+   <fmt:param value="${currentDate}"/>
+  </fmt:message>
+ </li>
+
+ <fmt:setLocale value="en"/>
+ <fmt:setBundle basename="org.apache.taglibs.standard.examples.i18n.Resources" var="enBundle"/>
+ <li>Locale set to English yields a locale-less localization context. Formatting still done
+     using the preferred locale:<br>
+  <fmt:message key="currentTime" bundle="${esBundle}">
+   <fmt:param value="${currentDate}"/>
+  </fmt:message>
+ </li>
+</ul>
+
+</body>
+</html>
diff --git a/standard/examples/web/format/PrefixAttribute.jsp b/standard/examples/web/format/PrefixAttribute.jsp
new file mode 100644
index 0000000..12466ff
--- /dev/null
+++ b/standard/examples/web/format/PrefixAttribute.jsp
@@ -0,0 +1,16 @@
+<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
+
+<html>
+<head>
+  <title>JSTL: Formatting/I18N Support -- Prefix Attribute Example</title>
+</head>
+<body bgcolor="#FFFFFF">
+<h3>Prefix Attribute</h3>
+
+<fmt:setLocale value="de"/>
+<fmt:bundle basename="org.apache.taglibs.standard.examples.i18n.Resources" prefix="com.acme.labels.">
+ <fmt:message key="cancel"/>
+</fmt:bundle>
+
+</body>
+</html>
diff --git a/standard/examples/web/format/RequestEncoding.jsp b/standard/examples/web/format/RequestEncoding.jsp
new file mode 100644
index 0000000..cd51ecb
--- /dev/null
+++ b/standard/examples/web/format/RequestEncoding.jsp
@@ -0,0 +1,18 @@
+<html>
+<head>
+  <title>JSTL: Formatting/I18N Support -- Request Encoding Example</title>
+</head>
+<body bgcolor="#FFFFFF">
+This page contains two links, and sends German Umlaut characters as request
+parameter values to each of the linked pages.<br>
+Only one of the linked pages decodes and displays the request parameter values
+correctly:
+
+<ul>
+ <li><a href="GermanUmlautIncorrect.jsp?a_umlaut=%C3%A4&o_umlaut=%C3%B6&u_umlaut=%C3%BC">German Umlaut characters decoded incorrectly</a>
+ <li><a href="GermanUmlautCorrect.jsp?a_umlaut=%C3%A4&o_umlaut=%C3%B6&u_umlaut=%C3%BC">German Umlaut characters decoded correctly</a>
+</ul>
+
+</body>
+</html>
+
diff --git a/standard/examples/web/format/UndefinedKey.jsp b/standard/examples/web/format/UndefinedKey.jsp
new file mode 100644
index 0000000..4b46a6a
--- /dev/null
+++ b/standard/examples/web/format/UndefinedKey.jsp
@@ -0,0 +1,15 @@
+<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
+
+<html>
+<head>
+  <title>JSTL: Formatting/I18N Support -- Undefined Key Example</title>
+</head>
+<body bgcolor="#FFFFFF">
+<h3>Undefined Key</h3>
+
+<fmt:setLocale value="it"/>
+<fmt:setBundle basename="org.apache.taglibs.standard.examples.i18n.Resources" var="itBundle"/>
+<fmt:message key="invalidKey" bundle="${itBundle}"/>
+
+</body>
+</html>
diff --git a/standard/examples/web/format/index.html b/standard/examples/web/format/index.html
new file mode 100644
index 0000000..1477eed
--- /dev/null
+++ b/standard/examples/web/format/index.html
@@ -0,0 +1,89 @@
+<html><!-- #BeginTemplate "/Templates/ExamplesTemplate.dwt" -->
+<head>
+<!-- #BeginEditable "doctitle" --> 
+<title>JSTL: I18N-Capable Formatting Tags Examples</title>
+<!-- #EndEditable -->
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<link rel="stylesheet" href="../global.css" type="text/css">
+</head>
+
+<body bgcolor="#FFFFFF" text="#000000">
+<table width="100%" border="0" cellpadding="5">
+  <tr> 
+    <td height="0"><font color="#000099"><b>standard taglib • implementation 
+      of the JSP Standard Tag Library • </b></font><font color="#003399"><a href="mailto:taglibs-user at jakarta.apache.org"><b>support</b></a> 
+        <b><a href="mailto:taglibs-dev at jakarta.apache.org">development</a>   
+      <a href="mailto:jsr-52-comments at jcp.org">comments to JSR-52</a></b></font></td>
+  </tr>
+  <tr> 
+    <td bgcolor="#CCCCFF"><font size="-1">Examples     <a href="../index.html">Introduction</a> 
+      • <a href="../elsupport/index.html">General Purpose</a> 
+      • <a href="../conditionals/index.html">Conditionals</a> 
+      • <a href="../iterators/index.html">Iterators</a> • 
+      <a href="../import/index.jsp">Import</a> • <a href="index.html">I18N 
+      & Formatting</a> • <a href="../xml/index.html">XML</a> 
+      • <a href="../sql/index.jsp">SQL</a> • <a href="../functions/index.html">Functions</a> 
+      • <a href="../tlv/index.html">TLV</a> • <a href="../functions/index.html"></a><a href="../misc/index.html">Misc.</a></font></td>
+  </tr>
+</table>
+<!-- #BeginEditable "body" --> 
+<h2>I18N-Capable Formatting Tags Examples</h2>
+<h3>Demo <a href="../ShowSource.jsp?filename=/format/Demo.jsp"><img src="../images/code.gif" width="24" height="24" border="0"></a> 
+  <a href="Demo.jsp"><img src="../images/execute.gif" width="24" height="24" border="0"></a> </h3>
+Overview demo where the locale to be applied to the page may be changed dynamically.<br>
+<h3>German   <a href="../ShowSource.jsp?filename=/format/GermanLocale.jsp"><img src="../images/code.gif" width="24" height="24" border="0"></a> 
+  <a href="GermanLocale.jsp"><img src="../images/execute.gif" width="24" height="24" border="0"></a> 
+</h3>
+Using resource bundle for German locale. <br>
+<h3>Italian   <a href="../ShowSource.jsp?filename=/format/ItalianLocale.jsp"><img src="../images/code.gif" width="24" height="24" border="0"></a> 
+  <a href="ItalianLocale.jsp"><img src="../images/execute.gif" width="24" height="24" border="0"></a> 
+</h3>
+Using resource bundle for Italian locale. <br>
+<h3>Missing Resource Bundle   <a href="../ShowSource.jsp?filename=/format/MissingResourceBundle.jsp"><img src="../images/code.gif" width="24" height="24" border="0"></a> 
+  <a href="MissingResourceBundle.jsp"><img src="../images/execute.gif" width="24" height="24" border="0"></a> 
+</h3>
+Trying to access a resource bundle that does not exist. <br>
+<h3>Undefined Key   <a href="../ShowSource.jsp?filename=/format/UndefinedKey.jsp"><img src="../images/code.gif" width="24" height="24" border="0"></a> 
+  <a href="UndefinedKey.jsp"><img src="../images/execute.gif" width="24" height="24" border="0"></a> 
+</h3>
+Looking up an undefined key in a resource bundle. <br>
+<h3>Parametric Replacement   <a href="../ShowSource.jsp?filename=/format/ParametricReplacement.jsp"><img src="../images/code.gif" width="24" height="24" border="0"></a> 
+  <a href="ParametricReplacement.jsp"><img src="../images/execute.gif" width="24" height="24" border="0"></a> 
+</h3>
+Parametric replacement examples. <br>
+<h3>Prefix   <a href="../ShowSource.jsp?filename=/format/PrefixAttribute.jsp"><img src="../images/code.gif" width="24" height="24" border="0"></a> 
+  <a href="PrefixAttribute.jsp"><img src="../images/execute.gif" width="24" height="24" border="0"></a> 
+</h3>
+Prepending prefix to message key. <br>
+<h3>Date   <a href="../ShowSource.jsp?filename=/format/FormatDateTime.jsp"><img src="../images/code.gif" width="24" height="24" border="0"></a> 
+  <a href="FormatDateTime.jsp"><img src="../images/execute.gif" width="24" height="24" border="0"></a> 
+</h3>
+Formatting dates and times using <tt>en-US</tt> locale. <br>
+<h3>Date   <a href="../ShowSource.jsp?filename=/format/FormatDateTimeBrowserLocale.jsp"><img src="../images/code.gif" width="24" height="24" border="0"></a> 
+  <a href="FormatDateTimeBrowserLocale.jsp"><img src="../images/execute.gif" width="24" height="24" border="0"></a> 
+</h3>
+Formatting dates and times using browser-based locale. <br>
+<h3>Number   <a href="../ShowSource.jsp?filename=/format/FormatNumber.jsp"><img src="../images/code.gif" width="24" height="24" border="0"></a> 
+  <a href="FormatNumber.jsp"><img src="../images/execute.gif" width="24" height="24" border="0"></a> 
+</h3>
+Formatting numbers using <tt>en-US</tt> locale. <br>
+<h3>Number   <a href="../ShowSource.jsp?filename=/format/FormatNumberBrowserLocale.jsp"><img src="../images/code.gif" width="24" height="24" border="0"></a> 
+  <a href="FormatNumberBrowserLocale.jsp"><img src="../images/execute.gif" width="24" height="24" border="0"></a> 
+</h3>
+Formatting numbers using browser-based locale. <br>
+<h3>Request Parameter Decoding   <a href="../ShowSource.jsp?filename=/format/RequestEncoding.jsp"><img src="../images/code.gif" width="24" height="24" border="0"></a> 
+  <a href="RequestEncoding.jsp"><img src="../images/execute.gif" width="24" height="24" border="0"></a> 
+</h3>
+Decoding and displaying request parameters using the appropriate charset. <br>
+<!-- #EndEditable -->
+<hr noshade color="#000099">
+<table width="100%" border="0" cellpadding="5">
+  <tr> 
+    <td height="24"><font color="#000099"><b>standard taglib • implementation 
+      of the JSP Standard Tag Library • </b></font><font color="#003399"><a href="mailto:taglibs-user at jakarta.apache.org"><b>support</b></a> 
+        <b><a href="mailto:taglibs-dev at jakarta.apache.org">development</a>   
+      <a href="mailto:jsr-52-comments at jcp.org">comments to JSR-52</a></b></font></td>
+  </tr>
+</table>
+</body>
+<!-- #EndTemplate --></html>
diff --git a/standard/examples/web/functions/EscapeXml.jsp b/standard/examples/web/functions/EscapeXml.jsp
new file mode 100644
index 0000000..e760d43
--- /dev/null
+++ b/standard/examples/web/functions/EscapeXml.jsp
@@ -0,0 +1,39 @@
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
+
+<html>
+<head>
+  <title>JSTL Functions • Escape Xml</title>
+</head>
+<body bgcolor="#FFFFFF">
+
+<h2>Escape XML</h2>
+
+<c:set var="s1" value="There is a castle on a cloud"/>
+
+<h4>fn:escapeXml</h4>
+<table cellpadding="5" border="1">
+  <tr>
+    <th align="left">Input String</th>
+    <th>Result</th>
+  </tr>
+  <tr>
+    <td>${s1}</td>
+    <td>${fn:escapeXml(s1)}</td>
+  </tr>
+  <tr>
+    <td><foo>body of foo</foo></td>
+    <td>${fn:escapeXml("<foo>body of foo</foo>")}</td>
+  </tr>
+  <tr>
+    <td>null</td>
+    <td> ${fn:escapeXml(undefined)}</td>
+  </tr>
+  <tr>
+    <td>empty string</td>
+    <td> ${fn:escapeXml("")}</td>
+  </tr>
+</table>
+
+</body>
+</html>
diff --git a/standard/examples/web/functions/Length.jsp b/standard/examples/web/functions/Length.jsp
new file mode 100644
index 0000000..d61609f
--- /dev/null
+++ b/standard/examples/web/functions/Length.jsp
@@ -0,0 +1,37 @@
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
+
+<html>
+<head>
+  <title>JSTL Functions • Length</title>
+</head>
+<body bgcolor="#FFFFFF">
+
+<c:set var="s1" value="There is a castle on a cloud"/>
+
+<h4>fn:length</h4>
+<table cellpadding="5" border="1">
+  <tr>
+    <th align="left">Input String</th>
+    <th>Result</th>
+  </tr>
+  <tr>
+    <td>${s1}</td>
+    <td>${fn:length(s1)}</td>
+  </tr>
+  <tr>
+    <td>${customers}</td>
+    <td>${fn:length(customers)}</td>
+  </tr>
+  <tr>
+    <td>null</td>
+    <td>${fn:length(undefined)}</td>
+  </tr>
+  <tr>
+    <td>empty string</td>
+    <td>${fn:length("")}</td>
+  </tr>
+</table>
+
+</body>
+</html>
diff --git a/standard/examples/web/functions/Replace.jsp b/standard/examples/web/functions/Replace.jsp
new file mode 100644
index 0000000..8bb1329
--- /dev/null
+++ b/standard/examples/web/functions/Replace.jsp
@@ -0,0 +1,55 @@
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
+
+<html>
+<head>
+  <title>JSTL Functions • Replace</title>
+</head>
+<body bgcolor="#FFFFFF">
+
+<h2>Replace</h2>
+
+<c:set var="s1" value="There is a castle on a cloud"/>
+<c:set var="s2" value="one - two - three - one - two - three - one - two - three"/>
+<h4>fn:replace</h4>
+<table cellpadding="5" border="1">
+  <tr>
+    <th align="left">Input String</th>
+    <th>Substring Before</th>
+    <th>Substring After</th>
+    <th>Result</th>
+  </tr>
+  <tr>
+    <td>${s1}</td>
+    <td>e</td>
+    <td>*</td>
+    <td>${fn:replace(s1, "e", "*")}</td>
+  </tr>
+  <tr>
+    <td>${s2}</td>
+    <td>-</td>
+    <td>•</td>
+    <td>${fn:replace(s2, "-", "•")}</td>
+  </tr>
+  <tr>
+    <td>${s2}</td>
+    <td>two</td>
+    <td>empty</td>
+    <td>${fn:replace(s2, "two", "")}</td>
+  </tr>
+  <tr>
+    <td>${s2}</td>
+    <td>empty string</td>
+    <td>one</td>
+    <td>${fn:replace(s2, "", "one")}</td>
+  </tr>
+  <tr>
+    <td>null</td>
+    <td>one</td>
+    <td>two</td>
+    <td> ${fn:replace(undefined, "one", "two")}</td>
+  </tr>
+</table>
+
+</body>
+</html>
diff --git a/standard/examples/web/functions/SplitJoin.jsp b/standard/examples/web/functions/SplitJoin.jsp
new file mode 100644
index 0000000..d6cb162
--- /dev/null
+++ b/standard/examples/web/functions/SplitJoin.jsp
@@ -0,0 +1,87 @@
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
+<%@ taglib prefix="ex" uri="/jstl-examples-taglib" %>
+
+<html>
+<head>
+  <title>JSTL Functions • Split/Join</title>
+</head>
+<body bgcolor="#FFFFFF">
+
+<h2>Split/Join</h2>
+
+<c:set var="s1" value="There is a castle on a cloud"/>
+<c:set var="s3" value="one|two|three|four"/>
+<c:set var="s5" value="one|two+three*four"/>
+
+<h4>fn:split</h4>
+<table cellpadding="5" border="1">
+  <tr>
+    <th align="left">Input String</th>
+    <th>Delimiters</th>
+    <th>Result</th>
+  </tr>
+  <tr>
+    <td>${s1}</td>
+    <td>empty string</td>
+    <td>${ex:display(fn:split(s1, ""))}</td>
+  </tr>
+  <tr>
+    <td>${s3}</td>
+    <td>|</td>
+    <td>${ex:display(fn:split(s3, "|"))}</td>
+  </tr>
+  <tr>
+    <td>${s3}</td>
+    <td>+</td>
+    <td>${ex:display(fn:split(s3, "+"))}</td>
+  </tr>
+  <tr>
+    <td>${s5}</td>
+    <td>|+</td>
+    <td>${ex:display(fn:split(s5, "|+"))}</td>
+  </tr>
+  <tr>
+    <td>empty string</td>
+    <td>empty string</td>
+    <td> ${ex:display(fn:split("", ""))}</td>
+  </tr>
+</table>
+
+<c:set var="a1" value='${fn:split(s1, " ")}'/>
+<h4>fn:join</h4>
+<table cellpadding="5" border="1">
+  <tr>
+    <th align="left">Input Array</th>
+    <th>Separator</th>
+    <th>Result</th>
+  </tr>
+  <tr>
+    <td>${ex:display(a1)}</td>
+    <td> + </td>
+    <td>${fn:join(a1, " + ")}</td>
+  </tr>
+  <tr>
+    <td>${ex:display(a1)}</td>
+    <td><sep></td>
+    <td>${fn:join(a1, " <sep> ")}</td>
+  </tr>
+  <tr>
+    <td>${ex:display(a1)}</td>
+    <td>empty string</td>
+    <td>${fn:join(a1, "")}</td>
+  </tr>
+  <tr>
+    <td>${ex:display(a1)}</td>
+    <td>null</td>
+    <td>${fn:join(a1, null)}</td>
+  </tr>
+  <tr>
+    <td>null</td>
+    <td>empty string</td>
+    <td> ${fn:join(null, "")}</td>
+  </tr>
+</table>
+
+</body>
+</html>
diff --git a/standard/examples/web/functions/StringCapitalization.jsp b/standard/examples/web/functions/StringCapitalization.jsp
new file mode 100644
index 0000000..d4b56d8
--- /dev/null
+++ b/standard/examples/web/functions/StringCapitalization.jsp
@@ -0,0 +1,55 @@
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
+
+<html>
+<head>
+  <title>JSTL Functions • String Capitalization</title>
+</head>
+<body bgcolor="#FFFFFF">
+
+<h2>String Capitalization</h2>
+
+<c:set var="s1" value="There is a CASTLE on a CLOUD"/>
+
+<h4>fn:toLowerCase</h4>
+<table cellpadding="5" border="1">
+  <tr>
+    <th align="left">Input String</th>
+    <th>Result</th>
+  </tr>
+  <tr>
+    <td>${s1}</td>
+    <td>${fn:toLowerCase(s1)}</td>
+  </tr>
+  <tr>
+    <td>null</td>
+    <td> ${fn:toLowerCase(undefined)}</td>
+  </tr>
+  <tr>
+    <td>empty</td>
+    <td> ${fn:toLowerCase("")}</td>
+  </tr>
+</table>
+
+<h4>fn:toUpperCase</h4>
+<table cellpadding="5" border="1">
+  <tr>
+    <th align="left">Input String</th>
+    <th>Result</th>
+  </tr>
+  <tr>
+    <td>${s1}</td>
+    <td>${fn:toUpperCase(s1)}</td>
+  </tr>
+  <tr>
+    <td>null</td>
+    <td> ${fn:toUpperCase(undefined)}</td>
+  </tr>
+  <tr>
+    <td>empty</td>
+    <td> ${fn:toUpperCase("")}</td>
+  </tr>
+</table>
+
+</body>
+</html>
diff --git a/standard/examples/web/functions/StringSubset.jsp b/standard/examples/web/functions/StringSubset.jsp
new file mode 100644
index 0000000..7443849
--- /dev/null
+++ b/standard/examples/web/functions/StringSubset.jsp
@@ -0,0 +1,183 @@
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
+
+<html>
+<head>
+  <title>JSTL Functions • String Subset</title>
+</head>
+<body bgcolor="#FFFFFF">
+
+<h2>String Subset</h2>
+
+<c:set var="zip" value="75843-5643"/>
+<c:set var="s1" value="There is a castle on a cloud"/>
+
+<h4>fn:substring</h4>
+<table cellpadding="5" border="1">
+  <tr>
+    <th align="left">Input String</th>
+    <th>beginIndex</th>
+    <th>endIndex</th>
+    <th>Result</th>
+  </tr>
+  <tr>
+    <td>${zip}</td>
+    <td>6</td>
+    <td>-1</td>
+    <td>P.O. Box: ${fn:substring(zip, 6, -1)}</td>
+  </tr>
+  <tr>
+    <td>${s1}</td>
+    <td>11</td>
+    <td>17</td>
+    <td>${fn:substring(s1, 11, 17)}</td>
+  </tr>
+  <tr>
+    <td>${s1}</td>
+    <td>12</td>
+    <td>5</td>
+    <td> ${fn:substring(s1, 12, 5)}</td>
+  </tr>
+  <tr>
+    <td>${s1}</td>
+    <td>23</td>
+    <td>-1</td>
+    <td>${fn:substring(s1, 23, -1)}</td>
+  </tr>
+  <tr>
+    <td>${s1}</td>
+    <td>23</td>
+    <td>999</td>
+    <td>${fn:substring(s1, 23, 999)}</td>
+  </tr>
+  <tr>
+    <td>${s1}</td>
+    <td>-1</td>
+    <td>-1</td>
+    <td>${fn:substring(s1, -1, -1)}</td>
+  </tr>
+  <tr>
+    <td>${s1}</td>
+    <td>99</td>
+    <td>12</td>
+    <td> ${fn:substring(s1, 99, 12)}</td>
+  </tr>
+  <tr>
+    <td>empty string</td>
+    <td>2</td>
+    <td>6</td>
+    <td> ${fn:substring("", 2, 6)}</td>
+  </tr>
+  <tr>
+    <td>null</td>
+    <td>2</td>
+    <td>6</td>
+    <td> ${fn:substring(undefined, 2, 6)}</td>
+  </tr>
+</table>
+
+<h4>fn:substringAfter</h4>
+<table cellpadding="5" border="1">
+  <tr>
+    <th align="left">Input String</th>
+    <th>substring</th>
+    <th>Result</th>
+  </tr>
+  <tr>
+    <td>${zip}</td>
+    <td>-</td>
+    <td>P.O. Box: ${fn:substringAfter(zip, "-")}</td>
+  </tr>
+  <tr>
+    <td>${s1}</td>
+    <td>There</td>
+    <td>${fn:substringAfter(s1, "There")}</td>
+  </tr>
+  <tr>
+    <td>${s1}</td>
+    <td>on a</td>
+    <td>${fn:substringAfter(s1, "on a")}</td>
+  </tr>
+  <tr>
+    <td>${s1}</td>
+    <td>not found</td>
+    <td> ${fn:substringAfter(s1, "not found")}</td>
+  </tr>
+  <tr>
+    <td>${s1}</td>
+    <td>null</td>
+    <td>${fn:substringAfter(s1, undefined)}</td>
+  </tr>
+  <tr>
+    <td>${s1}</td>
+    <td>empty string</td>
+    <td>${fn:substringAfter(s1, "")}</td>
+  </tr>
+  <tr>
+    <td>empty string</td>
+    <td>castle</td>
+    <td> ${fn:substringAfter("", "castle")}</td>
+  </tr>
+  <tr>
+    <td>null</td>
+    <td>castle</td>
+    <td> ${fn:substringAfter(undefined, "castle")}</td>
+  </tr>
+  <tr>
+    <td>null</td>
+    <td>empty string</td>
+    <td> ${fn:substringAfter(undefined, "")}</td>
+  </tr>
+</table>
+
+<h4>fn:substringBefore</h4>
+<table cellpadding="5" border="1">
+  <tr>
+    <th align="left">Input String</th>
+    <th>substring</th>
+    <th>Result</th>
+  </tr>
+  <tr>
+    <td>${zip}</td>
+    <td>-</td>
+    <td>Zip without P.O. Box: ${fn:substringBefore(zip, "-")}</td>
+  </tr>
+  <tr>
+    <td>${s1}</td>
+    <td>on a</td>
+    <td>${fn:substringBefore(s1, "on a")}</td>
+  </tr>
+  <tr>
+    <td>${s1}</td>
+    <td>castle</td>
+    <td>${fn:substringBefore(s1, "castle")}</td>
+  </tr>
+  <tr>
+    <td>${s1}</td>
+    <td>null</td>
+    <td> ${fn:substringBefore(s1, undefined)}</td>
+  </tr>
+  <tr>
+    <td>${s1}</td>
+    <td>empty string</td>
+    <td> ${fn:substringBefore(s1, "")}</td>
+  </tr>
+  <tr>
+    <td>empty string</td>
+    <td>castle</td>
+    <td> ${fn:substringBefore("", "castle")}</td>
+  </tr>
+  <tr>
+    <td>null</td>
+    <td>castle</td>
+    <td> ${fn:substringBefore(undefined, "castle")}</td>
+  </tr>
+  <tr>
+    <td>null</td>
+    <td>empty string</td>
+    <td> ${fn:substringBefore(undefined, "")}</td>
+  </tr>
+</table>
+
+</body>
+</html>
diff --git a/standard/examples/web/functions/SubstringContained.jsp b/standard/examples/web/functions/SubstringContained.jsp
new file mode 100644
index 0000000..b16eee3
--- /dev/null
+++ b/standard/examples/web/functions/SubstringContained.jsp
@@ -0,0 +1,227 @@
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
+
+<html>
+<head>
+  <title>JSTL Functions • Substring Contained in String</title>
+</head>
+<body bgcolor="#FFFFFF">
+
+<h2>Substring Contained in String</h2>
+
+<c:set var="s1" value="There is a castle on a cloud"/>
+
+<h4>fn:contains</h4>
+<table cellpadding="5" border="1">
+  <tr>
+    <th align="left">Input String</th>
+    <th>Substring</th>
+    <th>Result</th>
+  </tr>
+  <tr>
+    <td>${s1}</td>
+    <td>castle</td>
+    <td>${fn:contains(s1, "castle")}</td>
+  </tr>
+  <tr>
+    <td>${s1}</td>
+    <td>CASTLE</td>
+    <td>${fn:contains(s1, "CASTLE")}</td>
+  </tr>
+  <tr>
+    <td>${s1}</td>
+    <td>null</td>
+    <td>${fn:contains(s1, undefined)}</td>
+  </tr>
+  <tr>
+    <td>${s1}</td>
+    <td>empty string</td>
+    <td>${fn:contains(s1, "")}</td>
+  </tr>
+  <tr>
+    <td>null</td>
+    <td>castle</td>
+    <td>${fn:contains(undefined, "castle")}</td>
+  </tr>
+  <tr>
+    <td>null</td>
+    <td>empty string</td>
+    <td>${fn:contains(undefined, "")}</td>
+  </tr>
+</table>
+
+<h4>fn:containsIgnoreCase</h4>
+<table cellpadding="5" border="1">
+  <tr>
+    <th align="left">Input String</th>
+    <th>Substring</th>
+    <th>Result</th>
+  </tr>
+  <tr>
+    <td>${s1}</td>
+    <td>castle</td>
+    <td>${fn:containsIgnoreCase(s1, "castle")}</td>
+  </tr>
+  <tr>
+    <td>${s1}</td>
+    <td>CASTLE</td>
+    <td>${fn:containsIgnoreCase(s1, "CASTLE")}</td>
+  </tr>
+  <tr>
+    <td>${s1}</td>
+    <td>CaStLe</td>
+    <td>${fn:containsIgnoreCase(s1, "CaStLe")}</td>
+  </tr>
+  <tr>
+    <td>${s1}</td>
+    <td>null</td>
+    <td>${fn:containsIgnoreCase(s1, undefined)}</td>
+  </tr>
+  <tr>
+    <td>${s1}</td>
+    <td>empty string</td>
+    <td>${fn:containsIgnoreCase(s1, "")}</td>
+  </tr>
+  <tr>
+    <td>null</td>
+    <td>castle</td>
+    <td>${fn:containsIgnoreCase(undefined, "castle")}</td>
+  </tr>
+  <tr>
+    <td>null</td>
+    <td>empty string</td>
+    <td>${fn:containsIgnoreCase(undefined, "")}</td>
+  </tr>
+</table>
+
+<h4>fn:startsWith</h4>
+<table cellpadding="5" border="1">
+  <tr>
+    <th align="left">Input String</th>
+    <th>Substring</th>
+    <th>Result</th>
+  </tr>
+  <tr>
+    <td>${s1}</td>
+    <td>castle</td>
+    <td>${fn:startsWith(s1, "castle")}</td>
+  </tr>
+  <tr>
+    <td>${s1}</td>
+    <td>There is</td>
+    <td>${fn:startsWith(s1, "There is")}</td>
+  </tr>
+  <tr>
+    <td>${s1}</td>
+    <td>null</td>
+    <td>${fn:startsWith(s1, undefined)}</td>
+  </tr>
+  <tr>
+    <td>${s1}</td>
+    <td>empty string</td>
+    <td>${fn:startsWith(s1, "")}</td>
+  </tr>
+  <tr>
+    <td>null</td>
+    <td>castle</td>
+    <td>${fn:startsWith(undefined, "castle")}</td>
+  </tr>
+  <tr>
+    <td>null</td>
+    <td>empty string</td>
+    <td>${fn:startsWith(undefined, "")}</td>
+  </tr>
+</table>
+
+<h4>fn:endsWith</h4>
+<table cellpadding="5" border="1">
+  <tr>
+    <th align="left">Input String</th>
+    <th>Substring</th>
+    <th>Result</th>
+  </tr>
+  <tr>
+    <td>${s1}</td>
+    <td>castle</td>
+    <td>${fn:endsWith(s1, "castle")}</td>
+  </tr>
+  <tr>
+    <td>${s1}</td>
+    <td>cloud</td>
+    <td>${fn:endsWith(s1, "cloud")}</td>
+  </tr>
+  <tr>
+    <td>${s1}</td>
+    <td>null</td>
+    <td>${fn:endsWith(s1, undefined)}</td>
+  </tr>
+  <tr>
+    <td>${s1}</td>
+    <td>empty string</td>
+    <td>${fn:endsWith(s1, "")}</td>
+  </tr>
+  <tr>
+    <td>null</td>
+    <td>castle</td>
+    <td>${fn:endsWith(undefined, "castle")}</td>
+  </tr>
+  <tr>
+    <td>null</td>
+    <td>empty string</td>
+    <td>${fn:endsWith(undefined, "")}</td>
+  </tr>
+</table>
+
+<h4>fn:indexOf</h4>
+<table cellpadding="5" border="1">
+  <tr>
+    <th align="left">Input String</th>
+    <th>Substring</th>
+    <th>Result</th>
+  </tr>
+  <tr>
+    <td>${s1}</td>
+    <td>castle</td>
+    <td>${fn:indexOf(s1, "castle")}</td>
+  </tr>
+  <tr>
+    <td>${s1}</td>
+    <td>cloud</td>
+    <td>${fn:indexOf(s1, "cloud")}</td>
+  </tr>
+  <tr>
+    <td>${s1}</td>
+    <td>null</td>
+    <td>${fn:indexOf(s1, undefined)}</td>
+  </tr>
+  <tr>
+    <td>${s1}</td>
+    <td>empty string</td>
+    <td>${fn:indexOf(s1, "")}</td>
+  </tr>
+  <tr>
+    <td>null</td>
+    <td>castle</td>
+    <td>${fn:indexOf(undefined, "castle")}</td>
+  </tr>
+  <tr>
+    <td>null</td>
+    <td>empty string</td>
+    <td>${fn:indexOf(undefined, "")}</td>
+  </tr>
+  <c:set var="text" value="Products List (2003/05/01)"/>
+  <tr>
+    <td colspan="3">Display text in between brackets</td>
+  </tr>
+  <tr>
+    <td>${text}</td>
+    <td>'(' and ')'</td>
+    <td>${fn:substring(text, fn:indexOf(text, '(')+1, fn:indexOf(text, ')'))}</td>
+  </tr>
+</table>
+
+<p>
+
+
+</body>
+</html>
diff --git a/standard/examples/web/functions/Trim.jsp b/standard/examples/web/functions/Trim.jsp
new file mode 100644
index 0000000..9a09f59
--- /dev/null
+++ b/standard/examples/web/functions/Trim.jsp
@@ -0,0 +1,48 @@
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
+
+<html>
+<head>
+  <title>JSTL Functions • Trim</title>
+</head>
+<body bgcolor="#FFFFFF">
+
+<h2>Trim</h2>
+
+<c:set var="s1" value="There is a castle on a cloud"/>
+<c:set var="custId" value=" 123 "/>
+
+<h4>fn:trim</h4>
+<table cellpadding="5" border="1">
+  <tr>
+    <th align="left">Input String</th>
+    <th>Result</th>
+  </tr>
+  <tr>
+    <td><pre>${custId} (whithout trim)</pre></td>
+    <td><c:url value="http://acme.com/cust"><c:param name="custId" value="${custId}"/></c:url></td>
+  </tr>
+  <tr>
+    <td><pre>${custId} (whith trim)</pre></td>
+    <td><c:url value="http://acme.com/cust"><c:param name="custId" value="${fn:trim(custId)}"/></c:url></td>
+  </tr>
+  <tr>
+    <td>${s1}</td>
+    <td>${fn:trim(s1)}</td>
+  </tr>
+  <tr>
+    <td><pre>    3 spaces before and after   </pre></td>
+    <td><pre>${fn:trim("    3 spaces before and after   ")}</pre></td>
+  </tr>
+  <tr>
+    <td>null</td>
+    <td> ${fn:trim(undefined)}</td>
+  </tr>
+  <tr>
+    <td>empty string</td>
+    <td> ${fn:trim("")}</td>
+  </tr>
+</table>
+
+</body>
+</html>
diff --git a/standard/examples/web/functions/index.html b/standard/examples/web/functions/index.html
new file mode 100644
index 0000000..c020a4d
--- /dev/null
+++ b/standard/examples/web/functions/index.html
@@ -0,0 +1,90 @@
+<html><!-- #BeginTemplate "/Templates/ExamplesTemplate.dwt" -->
+<head>
+<!-- #BeginEditable "doctitle" --> 
+<title>JSTL: Functions Tags Examples</title>
+<!-- #EndEditable -->
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<link rel="stylesheet" href="../global.css" type="text/css">
+</head>
+
+<body bgcolor="#FFFFFF" text="#000000">
+<table width="100%" border="0" cellpadding="5">
+  <tr> 
+    <td height="0"><font color="#000099"><b>standard taglib • implementation 
+      of the JSP Standard Tag Library • </b></font><font color="#003399"><a href="mailto:taglibs-user at jakarta.apache.org"><b>support</b></a> 
+        <b><a href="mailto:taglibs-dev at jakarta.apache.org">development</a>   
+      <a href="mailto:jsr-52-comments at jcp.org">comments to JSR-52</a></b></font></td>
+  </tr>
+  <tr> 
+    <td bgcolor="#CCCCFF"><font size="-1">Examples     <a href="../index.html">Introduction</a> 
+      • <a href="../elsupport/index.html">General Purpose</a> 
+      • <a href="../conditionals/index.html">Conditionals</a> 
+      • <a href="../iterators/index.html">Iterators</a> • 
+      <a href="../import/index.jsp">Import</a> • <a href="../format/index.html">I18N 
+      & Formatting</a> • <a href="../xml/index.html">XML</a> 
+      • <a href="../sql/index.jsp">SQL</a> • <a href="index.html">Functions</a> 
+      • <a href="../tlv/index.html">TLV</a> • <a href="index.html"></a><a href="../misc/index.html">Misc.</a></font></td>
+  </tr>
+</table>
+<!-- #BeginEditable "body" --> 
+<h2>Functions Examples</h2>
+
+<h3>Length of a Collection or a String   <a href="../ShowSource.jsp?filename=/functions/Length.jsp"><img src="../images/code.gif" width="24" height="24" border="0"></a> 
+  <a href="Length.jsp"><img src="../images/execute.gif" width="24" height="24" border="0"></a> 
+</h3>
+<code>length</code><br>
+
+<h3>String Capitalization    <a
+href="../ShowSource.jsp?filename=/functions/StringCapitalization.jsp"><img src="../images/code.gif" width="24" height="24" border="0"></a> 
+  <a href="StringCapitalization.jsp"><img src="../images/execute.gif" width="24" height="24" border="0"></a> 
+</h3>
+<code>toUpperCase toLowerCase</code><br>
+
+<h3>String Subset    <a
+href="../ShowSource.jsp?filename=/functions/StringSubset.jsp"><img src="../images/code.gif" width="24" height="24" border="0"></a> 
+  <a href="StringSubset.jsp"><img src="../images/execute.gif" width="24" height="24" border="0"></a> 
+</h3>
+<code>substring substringAfter substringBefore</code><br>
+
+<h3>Trim    <a
+href="../ShowSource.jsp?filename=/functions/Trim.jsp"><img src="../images/code.gif" width="24" height="24" border="0"></a> 
+  <a href="Trim.jsp"><img src="../images/execute.gif" width="24" height="24" border="0"></a> 
+</h3>
+<code>trim</code><br>
+
+<h3>Replace    <a
+href="../ShowSource.jsp?filename=/functions/Replace.jsp"><img src="../images/code.gif" width="24" height="24" border="0"></a> 
+  <a href="Replace.jsp"><img src="../images/execute.gif" width="24" height="24" border="0"></a> 
+</h3>
+<code>replace</code><br>
+
+<h3>Substring Contained in String    <a
+href="../ShowSource.jsp?filename=/functions/SubstringContained.jsp"><img src="../images/code.gif" width="24" height="24" border="0"></a> 
+  <a href="SubstringContained.jsp"><img src="../images/execute.gif" width="24" height="24" border="0"></a> 
+</h3>
+<code>contains containsIgnoreCase startsWith endsWith indexOf</code><br>
+
+<h3>Split/Join    <a
+href="../ShowSource.jsp?filename=/functions/SplitJoin.jsp"><img src="../images/code.gif" width="24" height="24" border="0"></a> 
+  <a href="SplitJoin.jsp"><img src="../images/execute.gif" width="24" height="24" border="0"></a> 
+</h3>
+<code>split join</code><br>
+
+<h3>EscapeXml    <a
+href="../ShowSource.jsp?filename=/functions/EscapeXml.jsp"><img src="../images/code.gif" width="24" height="24" border="0"></a> 
+  <a href="EscapeXml.jsp"><img src="../images/execute.gif" width="24" height="24" border="0"></a> 
+</h3>
+<code>escapeXml</code><br>
+
+<!-- #EndEditable -->
+<hr noshade color="#000099">
+<table width="100%" border="0" cellpadding="5">
+  <tr> 
+    <td height="24"><font color="#000099"><b>standard taglib • implementation 
+      of the JSP Standard Tag Library • </b></font><font color="#003399"><a href="mailto:taglibs-user at jakarta.apache.org"><b>support</b></a> 
+        <b><a href="mailto:taglibs-dev at jakarta.apache.org">development</a>   
+      <a href="mailto:jsr-52-comments at jcp.org">comments to JSR-52</a></b></font></td>
+  </tr>
+</table>
+</body>
+<!-- #EndTemplate --></html>
diff --git a/standard/examples/web/global.css b/standard/examples/web/global.css
new file mode 100644
index 0000000..6bc32ce
--- /dev/null
+++ b/standard/examples/web/global.css
@@ -0,0 +1,4 @@
+body {  font-family: Arial, Helvetica, sans-serif}
+h1 {  color: #000099}
+h2 {  color: #000099}
+h3 {  color: #000099}
diff --git a/standard/examples/web/images/code.gif b/standard/examples/web/images/code.gif
new file mode 100644
index 0000000..93af2cd
Binary files /dev/null and b/standard/examples/web/images/code.gif differ
diff --git a/standard/examples/web/images/execute.gif b/standard/examples/web/images/execute.gif
new file mode 100644
index 0000000..f64d70f
Binary files /dev/null and b/standard/examples/web/images/execute.gif differ
diff --git a/standard/examples/web/images/return.gif b/standard/examples/web/images/return.gif
new file mode 100644
index 0000000..af4f68f
Binary files /dev/null and b/standard/examples/web/images/return.gif differ
diff --git a/standard/examples/web/import/Absolute.jsp b/standard/examples/web/import/Absolute.jsp
new file mode 100644
index 0000000..d85988f
--- /dev/null
+++ b/standard/examples/web/import/Absolute.jsp
@@ -0,0 +1,19 @@
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<%@ taglib prefix="ex" uri="/jstl-examples-taglib" %>
+
+<html>
+<head>
+  <title>JSTL: I/O Support -- Absolute URL Example</title>
+</head>
+<body bgcolor="#FFFFFF">
+<h3>Absolute URL</h3>
+
+<h4>CNN's RSS XML feed:</h4>
+<blockquote>
+<ex:escapeHtml>
+  <c:import url="http://www.cnn.com/cnn.rss"/>
+</ex:escapeHtml>
+</blockquote>
+
+</body>
+</html>
diff --git a/standard/examples/web/import/AbsoluteFtp.jsp b/standard/examples/web/import/AbsoluteFtp.jsp
new file mode 100644
index 0000000..d5e0a86
--- /dev/null
+++ b/standard/examples/web/import/AbsoluteFtp.jsp
@@ -0,0 +1,18 @@
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+
+<html>
+<head>
+  <title>JSTL: I/O Support -- Absolute URL Example (non-HTTP)</title>
+</head>
+<body bgcolor="#FFFFFF">
+<h3>Absolute URL (non-HTTP)</h3>
+
+<h4>Free Software Foundation's FTP site:</h4>
+<blockquote>
+ <pre>
+  <c:import url="ftp://ftp.gnu.org/README"/>
+ </pre>
+</blockquote>
+
+</body>
+</html>
diff --git a/standard/examples/web/import/ContextRelative.jsp b/standard/examples/web/import/ContextRelative.jsp
new file mode 100644
index 0000000..3056d57
--- /dev/null
+++ b/standard/examples/web/import/ContextRelative.jsp
@@ -0,0 +1,20 @@
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+
+<html>
+<head>
+  <title>JSTL: I/O Support -- Context-relative URL example</title>
+</head>
+<body bgcolor="#FFFFFF">
+Assuming you have the "examples" webapp installed, here's a file from it...
+
+URL:<c:out value="${_contextUrl}"/><br>
+Name:<c:out value="${_contextName}"/>
+
+<blockquote>
+ <pre>
+  <c:import url="${_contextUrl}" context="${_contextName}"/>
+ </pre>
+</blockquote>
+
+</body>
+</html>
diff --git a/standard/examples/web/import/Encode.jsp b/standard/examples/web/import/Encode.jsp
new file mode 100644
index 0000000..ec8d28a
--- /dev/null
+++ b/standard/examples/web/import/Encode.jsp
@@ -0,0 +1,47 @@
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+
+<html>
+<head>
+  <title>JSTL: I/O Support -- URL Encoding Example</title>
+</head>
+<body bgcolor="#FFFFFF">
+<h3>URL Encoding</h3>
+
+<h4><c:url></h4>
+
+Disable cookies in your browser to see URL rewriting.
+
+<table border="1" bgcolor="#dddddd">
+ <tr>
+  <td>"base", param=ABC</td>
+  <td><c:url value="base"><c:param name="param" value="ABC"/></c:url></td>
+ </tr>
+ <tr>
+  <td>"base", param=123</td>
+  <td><c:url value="base"><c:param name="param" value="123"/></c:url></td>
+ </tr>
+ <tr>
+  <td>"base", param=&</td>
+  <td><c:url value="base"><c:param name="param" value="&"/></c:url></td>
+ </tr>
+ <tr>
+  <td>"base", param="JSTL is fun"</td>
+  <td><c:url value="base"><c:param name="param" value="JSTL is fun"/></c:url></td>
+ </tr>
+ <tr>
+  <td>"base", param="�@foo-bar"</td>
+  <td><c:url value="base"><c:param name="param" value="�@foo-bar"/></c:url></td>
+ </tr>
+ <tr>
+  <td>"base", m�t�o="l�g�re pluie @ Saint-Denis-de-la-R�union"</td>
+  <td><c:url value="base"><c:param name="m�t�o" value="l�g�re pluie @ Saint-Denis-de-la-R�union"/></c:url></td>
+ </tr>
+</table>
+
+<p>
+Compose the url, then use it in an HTML anchor tag: 
+<c:url var="url" value="Encode.jsp">
+  <c:param name="arg1" value="value of arg1"/>
+  <c:param name="arg2" value="value of arg2"/>
+</c:url>
+<a href='<c:out value="${url}"/>'>Link back to this page (<c:out value="${url}"/>)</a>
\ No newline at end of file
diff --git a/standard/examples/web/import/EncodeContextRelative.jsp b/standard/examples/web/import/EncodeContextRelative.jsp
new file mode 100644
index 0000000..947b06d
--- /dev/null
+++ b/standard/examples/web/import/EncodeContextRelative.jsp
@@ -0,0 +1,20 @@
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+
+<html>
+<head>
+  <title>JSTL: I/O Support -- URL Encoding Example</title>
+</head>
+<body bgcolor="#FFFFFF">
+<h3>URL Encoding</h3>
+
+<h4><urlEncode></h4>
+
+<c:url var="param1" value="${_paramValue1}"/>
+<c:url var="param2" value="${_paramValue2}"/>
+<c:url var="param3" value="${_paramValue3}"/>
+<c:out value="${_contextUrl}" />
+<c:import url="${_contextUrl}" context="${_contextName}">
+    <c:param name="${_paramName1}" value="${param1}"/>
+    <c:param name="${_paramName2}" value="${param2}"/>
+    <c:param name="${_paramName3}" value="${param3}"/>
+</c:import> 
diff --git a/standard/examples/web/import/ExposeString.jsp b/standard/examples/web/import/ExposeString.jsp
new file mode 100644
index 0000000..a2ffa74
--- /dev/null
+++ b/standard/examples/web/import/ExposeString.jsp
@@ -0,0 +1,20 @@
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+
+<html>
+<head>
+  <title>JSTL: I/O Support -- String exposure</title>
+</head>
+<body bgcolor="#FFFFFF">
+<h3>String exposure</h3>
+
+<c:import var="cnn" url="http://www.cnn.com/cnn.rss"/>
+
+<h4>CNN's RSS XML feed:</h4>
+<blockquote>
+ <pre>
+  <c:out value="${cnn}"/>
+ </pre>
+</blockquote>
+
+</body>
+</html>
diff --git a/standard/examples/web/import/ExposeStringRelative.jsp b/standard/examples/web/import/ExposeStringRelative.jsp
new file mode 100644
index 0000000..409c9b4
--- /dev/null
+++ b/standard/examples/web/import/ExposeStringRelative.jsp
@@ -0,0 +1,17 @@
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+
+<html>
+<head>
+  <title>JSTL: I/O Support -- String exposure for relative URL</title>
+</head>
+<body bgcolor="#FFFFFF">
+<h3>String exposure for relative URL</h3>
+
+<h4>Escaped (raw HTML)</h4>
+
+<c:import var="cnn" url="LocalSample.jsp"/>
+
+<c:out value="${cnn}"/>
+
+</body>
+</html>
diff --git a/standard/examples/web/import/LocalSample.jsp b/standard/examples/web/import/LocalSample.jsp
new file mode 100644
index 0000000..f46ef66
--- /dev/null
+++ b/standard/examples/web/import/LocalSample.jsp
@@ -0,0 +1,14 @@
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+
+<html>
+<head>
+  <title>JSTL: I/O Support -- Simple static example to be included
+   in other pages</title>
+</head>
+<body bgcolor="#FFFFFF">
+<h3>Local example target page</h3>
+
+<h4>• This output comes from LocalSample.jsp • </h4>
+
+</body>
+</html>
diff --git a/standard/examples/web/import/Param.jsp b/standard/examples/web/import/Param.jsp
new file mode 100644
index 0000000..020259b
--- /dev/null
+++ b/standard/examples/web/import/Param.jsp
@@ -0,0 +1,13 @@
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+
+<%--
+  --   These URLs likely don't exist, but the error that gets reported 
+  --   back should help you see how <param> modifies the URL.
+  --
+  --%>
+
+<c:import url="http://localhost/foo" charEncoding="foo">
+  <c:param name="a" value="b"/>
+  <c:param name="c" value="d"/>
+  <c:param name="equals" value="="/>                      <%-- encoded --%>
+</c:import>
diff --git a/standard/examples/web/import/Relative.jsp b/standard/examples/web/import/Relative.jsp
new file mode 100644
index 0000000..35c6c68
--- /dev/null
+++ b/standard/examples/web/import/Relative.jsp
@@ -0,0 +1,18 @@
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+
+<html>
+<head>
+  <title>JSTL: I/O Support -- Relative URL Example</title>
+</head>
+<body bgcolor="#FFFFFF">
+<h3>Relative URL</h3>
+
+<h4>Import from current directory:</h4>
+<blockquote>
+ <pre>
+  <c:import url="LocalSample.jsp"/>
+ </pre>
+</blockquote>
+
+</body>
+</html>
diff --git a/standard/examples/web/import/StartSlash.jsp b/standard/examples/web/import/StartSlash.jsp
new file mode 100644
index 0000000..1a9ea8d
--- /dev/null
+++ b/standard/examples/web/import/StartSlash.jsp
@@ -0,0 +1,16 @@
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+
+<html>
+<head>
+  <title>JSTL: I/O Support -- Malformed URL example</title>
+</head>
+<body bgcolor="#FFFFFF">
+
+<blockquote>
+ <pre>
+  <c:import url="jsp/simpletag/foo.jsp" context="/examples"/>
+ </pre>
+</blockquote>
+
+</body>
+</html>
diff --git a/standard/examples/web/import/index.html b/standard/examples/web/import/index.html
new file mode 100644
index 0000000..cab8453
--- /dev/null
+++ b/standard/examples/web/import/index.html
@@ -0,0 +1,99 @@
+<html><!-- #BeginTemplate "/Templates/ExamplesTemplate.dwt" -->
+<head>
+<!-- #BeginEditable "doctitle" --> 
+<title>JSTL: Import Tags Examples</title>
+<!-- #EndEditable -->
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<link rel="stylesheet" href="../global.css" type="text/css">
+</head>
+
+<body bgcolor="#FFFFFF" text="#000000">
+<table width="100%" border="0" cellpadding="5">
+  <tr> 
+    <td height="0"><font color="#000099"><b>standard taglib • implementation 
+      of the JSP Standard Tag Library • </b></font><font color="#003399"><a href="mailto:taglibs-user at jakarta.apache.org"><b>support</b></a> 
+        <b><a href="mailto:taglibs-dev at jakarta.apache.org">development</a>   
+      <a href="mailto:jsr-52-comments at jcp.org">comments to JSR-52</a></b></font></td>
+  </tr>
+  <tr> 
+    <td bgcolor="#CCCCFF"><font size="-1">Examples     <a href="../index.html">Introduction</a> 
+      • <a href="../elsupport/index.html">General Purpose</a> 
+      • <a href="../conditionals/index.html">Conditionals</a> 
+      • <a href="../iterators/index.html">Iterators</a> • 
+      <a href="index.jsp">Import</a> • <a href="../format/index.html">I18N 
+      & Formatting</a> • <a href="../xml/index.html">XML</a> 
+      • <a href="../sql/index.jsp">SQL</a> • <a href="../functions/index.html">Functions</a> 
+      • <a href="../tlv/index.html">TLV</a> • <a href="../functions/index.html"></a><a href="../misc/index.html">Misc.</a></font></td>
+  </tr>
+</table>
+<!-- #BeginEditable "body" --> 
+<h2>Import Tags Examples</h2>
+<p>If you are using a Proxy server, you will need to set the following System 
+  Properties when starting the VM:</p>
+<pre>
+    http.proxyHost
+    http.proxyPort
+    ftp.proxyHost
+    ftp.proxyPort
+</pre>
+<br>
+<h3>Absolute   <a href="../ShowSource.jsp?filename=/import/Absolute.jsp"><img src="../images/code.gif" width="24" height="24" border="0"></a> 
+  <a href="Absolute.jsp"><img src="../images/execute.gif" width="24" height="24" border="0"></a> 
+</h3>
+Using an Absolute URL to import a resource. <br>
+<h3>Relative   <a href="../ShowSource.jsp?filename=/import/Relative.jsp"><img src="../images/code.gif" width="24" height="24" border="0"></a> 
+  <a href="Relative.jsp"><img src="../images/execute.gif" width="24" height="24" border="0"></a> 
+</h3>
+Using a Relative URL to import a resource. <br>
+<h3>Context Relative   <a href="../ShowSource.jsp?filename=/import/ContextRelative.jsp"><img src="../images/code.gif" width="24" height="24" border="0"></a> 
+  <a href="ContextRelative.jsp"><img src="../images/execute.gif" width="24" height="24" border="0"></a> 
+</h3>
+Importing a resource relative to a foreign context. <br>
+<h3>Absolute (FTP)   <a href="../ShowSource.jsp?filename=/import/AbsoluteFtp.jsp"><img src="../images/code.gif" width="24" height="24" border="0"></a> 
+  <a href="AbsoluteFtp.jsp"><img src="../images/execute.gif" width="24" height="24" border="0"></a> 
+</h3>
+Using an Absolute URL to import a resource using a different protocol other than 
+HTTP. <br>
+<h3>Encode   <a href="../ShowSource.jsp?filename=/import/Encode.jsp"><img src="../images/code.gif" width="24" height="24" border="0"></a> 
+  <a href="Encode.jsp"><img src="../images/execute.gif" width="24" height="24" border="0"></a> 
+</h3>
+URL encoding examples. <br>
+<h3>Encode Context Relative   <a href="../ShowSource.jsp?filename=/import/EncodeContextRelative.jsp"><img src="../images/code.gif" width="24" height="24" border="0"></a> 
+  <a href="EncodeContextRelative.jsp"><img src="../images/execute.gif" width="24" height="24" border="0"></a> 
+</h3>
+URL encoding examples using a relative context and nested param tags. <br>
+<h3>Encode Query String   <a href="../ShowSource.jsp?filename=/import/EncodeQueryString.jsp"><img src="../images/code.gif" width="24" height="24" border="0"></a> 
+  <a href="EncodeQueryString.jsp"><img src="../images/execute.gif" width="24" height="24" border="0"></a> 
+</h3>
+URL encoding examples using a relative context and query string. <br>
+<h3>String Exposure Absolute   <a href="../ShowSource.jsp?filename=/import/ExposeString.jsp"><img src="../images/code.gif" width="24" height="24" border="0"></a> 
+  <a href="ExposeString.jsp"><img src="../images/execute.gif" width="24" height="24" border="0"></a> 
+</h3>
+Exposing the content of the resource as a String Object. <br>
+<h3>String Exposure Relative   <a href="../ShowSource.jsp?filename=/import/ExposeStringRelative.jsp"><img src="../images/code.gif" width="24" height="24" border="0"></a> 
+  <a href="ExposeStringRelative.jsp"><img src="../images/execute.gif" width="24" height="24" border="0"></a> 
+</h3>
+Exposing the content of a relative URL's resource as a String Object. <br>
+<h3>Param   <a href="../ShowSource.jsp?filename=/import/Param.jsp"><img src="../images/code.gif" width="24" height="24" border="0"></a> 
+  <a href="Param.jsp"><img src="../images/execute.gif" width="24" height="24" border="0"></a> 
+</h3>
+Using <param> element to specify request parameters. Also demonstrating how request 
+parameters can be URL encoded (default). (NOTE: Returns error page by default.) 
+<br>
+<h3>Malformed URL   <a href="../ShowSource.jsp?filename=/import/StartSlash.jsp"><img src="../images/code.gif" width="24" height="24" border="0"></a> 
+  <a href="StartSlash.jsp"><img src="../images/execute.gif" width="24" height="24" border="0"></a> 
+</h3>
+A relative URL must start with a "/" in a foreign context. (NOTE: This example 
+will result in a ServletException describing the error condition). <br>
+<!-- #EndEditable -->
+<hr noshade color="#000099">
+<table width="100%" border="0" cellpadding="5">
+  <tr> 
+    <td height="24"><font color="#000099"><b>standard taglib • implementation 
+      of the JSP Standard Tag Library • </b></font><font color="#003399"><a href="mailto:taglibs-user at jakarta.apache.org"><b>support</b></a> 
+        <b><a href="mailto:taglibs-dev at jakarta.apache.org">development</a>   
+      <a href="mailto:jsr-52-comments at jcp.org">comments to JSR-52</a></b></font></td>
+  </tr>
+</table>
+</body>
+<!-- #EndTemplate --></html>
diff --git a/standard/examples/web/import/index.jsp b/standard/examples/web/import/index.jsp
new file mode 100644
index 0000000..9fb24ee
--- /dev/null
+++ b/standard/examples/web/import/index.jsp
@@ -0,0 +1,94 @@
+<html><!-- #BeginTemplate "/Templates/ExamplesTemplate.dwt" -->
+<head>
+<!-- #BeginEditable "doctitle" --> 
+<title>JSTL: Import Tags Examples</title>
+<!-- #EndEditable -->
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<link rel="stylesheet" href="../global.css" type="text/css">
+</head>
+
+<body bgcolor="#FFFFFF" text="#000000">
+<table width="100%" border="0" cellpadding="5">
+  <tr> 
+    <td height="0"><font color="#000099"><b>standard taglib • implementation 
+      of the JSP Standard Tag Library • </b></font><font color="#003399"><a href="mailto:taglibs-user at jakarta.apache.org"><b>support</b></a> 
+        <b><a href="mailto:taglibs-dev at jakarta.apache.org">development</a>   
+      <a href="mailto:jsr-52-comments at jcp.org">comments to JSR-52</a></b></font></td>
+  </tr>
+  <tr> 
+    <td bgcolor="#CCCCFF"><font size="-1">Examples     <a href="../index.html">Introduction</a> 
+      • <a href="../elsupport/index.html">General Purpose</a> 
+      • <a href="../conditionals/index.html">Conditionals</a> 
+      • <a href="../iterators/index.html">Iterators</a> • 
+      <a href="index.jsp">Import</a> • <a href="../format/index.html">I18N 
+      & Formatting</a> • <a href="../xml/index.html">XML</a> 
+      • <a href="../sql/index.jsp">SQL</a> • <a href="../functions/index.html">Functions</a> 
+      • <a href="../tlv/index.html">TLV</a> • <a href="../functions/index.html"></a><a href="../misc/index.html">Misc.</a></font></td>
+  </tr>
+</table>
+<!-- #BeginEditable "body" --> 
+<%@ include file="links.html" %>
+<h2>Context Relative Examples</h2>
+<p>For the context relative examples you will need to supply an available relative 
+  context name and url before executing the tags.</p>
+<form name="myform" action="session.jsp" method="get" >
+  <table width="90%" border="0" cellspacing="0" cellpadding="0">
+    <tr> 
+      <td>Context</td>
+      <td> 
+        <input type="text" size="40" name="contextName" value="/examples">
+      </td>
+    </tr>
+    <tr> 
+      <td>Url</td>
+      <td> 
+        <input type="text" size="40" name="contextUrl" value="/jsp/simpletag/foo.jsp">
+      </td>
+    </tr>
+    <tr> 
+      <td>Param name:</td>
+      <td>
+        <input type="text" size="40" name="paramName1">
+      </td>
+      <td>Param value:</td>
+      <td>
+        <input type="text" size="40" name="paramValue1">
+      </td>
+    </tr>
+    <tr> 
+      <td>Param name:</td>
+      <td>
+        <input type="text" size="40" name="paramName2">
+      </td>
+      <td>Param value:</td>
+      <td>
+        <input type="text" size="40" name="paramValue2">
+      </td>
+    </tr>
+    <tr> 
+      <td>Param name:</td>
+      <td>
+        <input type="text" size="40" name="paramName3">
+      </td>
+      <td>Param value:</td>
+      <td>
+        <input type="text" size="40" name="paramValue3">
+      </td>
+    </tr>
+  </table>
+  <p> 
+    <input type="submit" name="Submit" value="Submit">
+  </p>
+</form>
+<!-- #EndEditable -->
+<hr noshade color="#000099">
+<table width="100%" border="0" cellpadding="5">
+  <tr> 
+    <td height="24"><font color="#000099"><b>standard taglib • implementation 
+      of the JSP Standard Tag Library • </b></font><font color="#003399"><a href="mailto:taglibs-user at jakarta.apache.org"><b>support</b></a> 
+        <b><a href="mailto:taglibs-dev at jakarta.apache.org">development</a>   
+      <a href="mailto:jsr-52-comments at jcp.org">comments to JSR-52</a></b></font></td>
+  </tr>
+</table>
+</body>
+<!-- #EndTemplate --></html>
diff --git a/standard/examples/web/import/links.html b/standard/examples/web/import/links.html
new file mode 100644
index 0000000..afad4ab
--- /dev/null
+++ b/standard/examples/web/import/links.html
@@ -0,0 +1,46 @@
+<h2>Import Tags Examples</h2>
+<p>If you are using a Proxy server, you will need to set the following System 
+  Properties when starting the VM:</p>
+<pre>
+    http.proxyHost
+    http.proxyPort
+    ftp.proxyHost
+    ftp.proxyPort
+</pre>
+<br>
+<h3>Absolute   <a href="../ShowSource.jsp?filename=/import/Absolute.jsp"><img src="../images/code.gif" width="24" height="24" border="0"></a> 
+  <a href="Absolute.jsp"><img src="../images/execute.gif" width="24" height="24" border="0"></a> 
+</h3>
+Using an Absolute URL to import a resource. <br>
+<h3>Relative   <a href="../ShowSource.jsp?filename=/import/Relative.jsp"><img src="../images/code.gif" width="24" height="24" border="0"></a> 
+  <a href="Relative.jsp"><img src="../images/execute.gif" width="24" height="24" border="0"></a> 
+</h3>
+Using a Relative URL to import a resource. <br>
+<h3>Absolute (FTP)   <a href="../ShowSource.jsp?filename=/import/AbsoluteFtp.jsp"><img src="../images/code.gif" width="24" height="24" border="0"></a> 
+  <a href="AbsoluteFtp.jsp"><img src="../images/execute.gif" width="24" height="24" border="0"></a> 
+</h3>
+Using an Absolute URL to import a resource using a different protocol other than 
+HTTP. <br>
+<h3>Encode   <a href="../ShowSource.jsp?filename=/import/Encode.jsp"><img src="../images/code.gif" width="24" height="24" border="0"></a> 
+  <a href="Encode.jsp"><img src="../images/execute.gif" width="24" height="24" border="0"></a> 
+</h3>
+URL encoding examples. <br>
+<h3>String Exposure Absolute   <a href="../ShowSource.jsp?filename=/import/ExposeString.jsp"><img src="../images/code.gif" width="24" height="24" border="0"></a> 
+  <a href="ExposeString.jsp"><img src="../images/execute.gif" width="24" height="24" border="0"></a> 
+</h3>
+Exposing the content of the resource as a String Object. <br>
+<h3>String Exposure Relative   <a href="../ShowSource.jsp?filename=/import/ExposeStringRelative.jsp"><img src="../images/code.gif" width="24" height="24" border="0"></a> 
+  <a href="ExposeStringRelative.jsp"><img src="../images/execute.gif" width="24" height="24" border="0"></a> 
+</h3>
+Exposing the content of a relative URL's resource as a String Object. <br>
+<h3>Param   <a href="../ShowSource.jsp?filename=/import/Param.jsp"><img src="../images/code.gif" width="24" height="24" border="0"></a> 
+  <a href="Param.jsp"><img src="../images/execute.gif" width="24" height="24" border="0"></a> 
+</h3>
+Using <param> element to specify request parameters. Also demonstrating how request 
+parameters can be URL encoded (default). (NOTE: Returns error page that shows 
+how request parameters are encoded) <br>
+<h3>Malformed URL   <a href="../ShowSource.jsp?filename=/import/StartSlash.jsp"><img src="../images/code.gif" width="24" height="24" border="0"></a> 
+  <a href="StartSlash.jsp"><img src="../images/execute.gif" width="24" height="24" border="0"></a> 
+</h3>
+A relative URL must start with a "/" in a foreign context. (NOTE: This example 
+will result in a ServletException describing the error condition). <br>
diff --git a/standard/examples/web/import/relativeLinks.html b/standard/examples/web/import/relativeLinks.html
new file mode 100644
index 0000000..0d6f53d
--- /dev/null
+++ b/standard/examples/web/import/relativeLinks.html
@@ -0,0 +1,10 @@
+<h2>Import Tags Context Relative Examples</h2>
+
+<h3>Context Relative   <a href="../ShowSource.jsp?filename=/import/ContextRelative.jsp"><img src="../images/code.gif" width="24" height="24" border="0"></a> 
+  <a href="ContextRelative.jsp"><img src="../images/execute.gif" width="24" height="24" border="0"></a> 
+</h3>
+Importing a resource relative to a foreign context. <br>
+<h3>Encode Context Relative   <a href="../ShowSource.jsp?filename=/import/EncodeContextRelative.jsp"><img src="../images/code.gif" width="24" height="24" border="0"></a> 
+  <a href="EncodeContextRelative.jsp"><img src="../images/execute.gif" width="24" height="24" border="0"></a> 
+</h3>
+URL encoding examples using a relative context and nested param tags. <br>
diff --git a/standard/examples/web/import/session.jsp b/standard/examples/web/import/session.jsp
new file mode 100644
index 0000000..2ab5310
--- /dev/null
+++ b/standard/examples/web/import/session.jsp
@@ -0,0 +1,33 @@
+<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
+
+<html>
+<head>
+   <title>Jakarta DBTAGS Taglib Example</title>
+</head>
+<body bgcolor="white">
+
+<%
+  String _param = request.getParameter("contextName");
+  session.setAttribute("_contextName", _param);
+  _param = request.getParameter("contextUrl");
+  session.setAttribute("_contextUrl", _param);
+
+  _param = request.getParameter("paramValue1");
+  session.setAttribute("_paramValue1", _param);
+  _param = request.getParameter("paramValue2");
+  session.setAttribute("_paramValue2", _param);
+  _param = request.getParameter("paramValue3");
+  session.setAttribute("_paramValue3", _param);
+
+  _param = request.getParameter("paramName1");
+  session.setAttribute("_paramName1", _param);
+  _param = request.getParameter("paramName2");
+  session.setAttribute("_paramName2", _param);
+  _param = request.getParameter("paramName3");
+  session.setAttribute("_paramName3", _param);
+%>
+
+<%@ include file="relativeLinks.html" %>
+
+</body>
+</html>
diff --git a/standard/examples/web/index.html b/standard/examples/web/index.html
new file mode 100644
index 0000000..3bb8b66
--- /dev/null
+++ b/standard/examples/web/index.html
@@ -0,0 +1,142 @@
+<html><!-- #BeginTemplate "/Templates/ExamplesTemplate.dwt" -->
+<head>
+<!-- #BeginEditable "doctitle" --> 
+<title>JSTL: Examples Web Application</title>
+<!-- #EndEditable -->
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<link rel="stylesheet" href="global.css" type="text/css">
+</head>
+
+<body bgcolor="#FFFFFF" text="#000000">
+<table width="100%" border="0" cellpadding="5">
+  <tr> 
+    <td height="0"><font color="#000099"><b>standard taglib • implementation 
+      of the JSP Standard Tag Library • </b></font><font color="#003399"><a href="mailto:taglibs-user at jakarta.apache.org"><b>support</b></a> 
+        <b><a href="mailto:taglibs-dev at jakarta.apache.org">development</a>   
+      <a href="mailto:jsr-52-comments at jcp.org">comments to JSR-52</a></b></font></td>
+  </tr>
+  <tr> 
+    <td bgcolor="#CCCCFF"><font size="-1">Examples     <a href="index.html">Introduction</a> 
+      • <a href="elsupport/index.html">General Purpose</a> 
+      • <a href="conditionals/index.html">Conditionals</a> 
+      • <a href="iterators/index.html">Iterators</a> • 
+      <a href="import/index.jsp">Import</a> • <a href="format/index.html">I18N 
+      & Formatting</a> • <a href="xml/index.html">XML</a> 
+      • <a href="sql/index.jsp">SQL</a> • <a href="functions/index.html">Functions</a> 
+      • <a href="tlv/index.html">TLV</a> • <a href="functions/index.html"></a><a href="misc/index.html">Misc.</a></font></td>
+  </tr>
+</table>
+<!-- #BeginEditable "body" --> 
+<h2>Welcome to the standard-examples web application!</h2>
+<p>This web application includes a variety of sample JSP pages that showcase the 
+  JSTL tags specified within the <a href="http://www.jcp.org/jsr/detail/52.jsp">JSR-052 
+  Expert Group</a>. 
+<h3>Documentation</h3>
+<p>The <a
+href="http://www.jcp.org/aboutJava/communityprocess/final/jsr052/index2.html">JSTL 
+  1.1 Specification</a> developed by the JSR052 expert group under the <a href="http://www.jcp.org">Java 
+  Community Process</a> is a complete JSTL 1.1 reference.</p>
+<p>Documentation on the JSTL tags is available at <a href="http://jakarta.apache.org/taglibs/doc/standard-doc">http://jakarta.apache.org/taglibs/doc/standard-doc</a>. 
+  It is also available as the standard-doc web application of the standard taglib 
+  release. 
+<h3>Mailing Lists</h3>
+<p>There are three ways to obtain information from or send your comments: 
+<ol>
+  <li><b>Support</b>: For support/usage questions, please use the <a href="mailto:taglibs-user at jakarta.apache.org">user 
+    mailing list</a> of jakarta-taglibs. </li>
+  <li><b>Development</b>: For bugs, development related questions, please use 
+    the <a href="mailto:taglibs-dev at jakarta.apache.org">developer mailing list</a> 
+    of jakarta-taglibs</li>
+  <li><b>Comments to the JSR052 EG</b>: To provide the Expert Group with feedback 
+    on JSTL, use either the <a href="mailto:taglibs-dev at jakarta.apache.org">developers 
+    mailing list</a> at Jakarta, or you may contact the expert group privately 
+    at <a href="mailto:jsr-52-comments at jcp.org">jsr-52-comments at jcp.org</a>. All 
+    comments will be read, but we cannot guarantee a personal reply to all messages 
+    received.</li>
+</ol>
+<h3>Examples</h3>
+<p>The JSTL examples have been divided in the following categories:</p>
+<ul>
+  <li><a href="elsupport/index.html">General Purpose Tags</a></li>
+  <li><a href="conditionals/index.html">Conditional Tags</a></li>
+  <li><a href="iterators/index.html">Iterator Tags</a></li>
+  <li><a href="import/index.jsp">Import Tags</a> </li>
+  <li><a href="format/index.html">I18N & Formatting Tags</a></li>
+  <li><a href="xml/index.html">XML Tags</a></li>
+  <li><a href="sql/index.jsp">SQL Tags</a></li>
+  <li><a href="functions/index.html">Functions</a></li>
+  <li><a href="tlv/index.html">Tag Library Validators</a></li>
+  <li><a href="misc/index.html">Miscellaneous</a></li>
+</ul>
+<p>The navigation bar at the top of each index page provides quick navigation 
+  to each set of example pages.</p>
+<p>When navigating the examples, the following icons will allow you to look at 
+  the source code as well as execute the example JSP page.</p>
+<table border="1" align="center" cellpadding="10">
+  <tr> 
+    <td width="30"><img src="images/code.gif"></td>
+    <td>Look at the source code of the example JSP page</td>
+  </tr>
+  <tr> 
+    <td width="30"><img src="images/execute.gif"></td>
+    <td>Execute the example JSP page</td>
+  </tr>
+</table>
+<h3>Infrastructure</h3>
+<p>The source code for the JSTL examples includes class <code>startup.Init</code> 
+  to initilialize the objects used in the examples. This allows us to mimic the 
+  environment that would normally be used within an MVC architecture: the Controller 
+  invokes the business logic, saves the objects required by the web application 
+  into JSP scoped attributes (usually request), and then invokes the proper JSP 
+  page. For the sake of this "examples" webapp, all objects are saved 
+  in the application scope.</p>
+<p>The application attributes are:</p>
+<ul>
+  <li><code>customers</code><br>
+    A collection of Customer objects</li>
+  <li><code>intArray</code><br>
+    An array of int's</li>
+  <li><code>stringArray</code><br>
+    An array of Strings</li>
+  <li><code>numberMap</code><br>
+    A Map instance associating Integer objects with their Spanish names</li>
+  <li><code>enumeration</code><br>
+    An enumeration on numberMap from above.<br>
+  </li>
+</ul>
+<p>The classes of interest that hold the information manipulated by the JSP pages 
+  are:</p>
+<ul>
+  <li>Customer 
+    <ul>
+      <li>int key</li>
+      <li>String lastName</li>
+      <li>String firstName</li>
+      <li>Date birthDate</li>
+      <li>Address address<br>
+        <br>
+      </li>
+    </ul>
+  </li>
+  <li>Address 
+    <ul>
+      <li>String line1</li>
+      <li>String line2</li>
+      <li>String city</li>
+      <li>String state</li>
+      <li>String country</li>
+    </ul>
+  </li>
+</ul>
+<!-- #EndEditable -->
+<hr noshade color="#000099">
+<table width="100%" border="0" cellpadding="5">
+  <tr> 
+    <td height="24"><font color="#000099"><b>standard taglib • implementation 
+      of the JSP Standard Tag Library • </b></font><font color="#003399"><a href="mailto:taglibs-user at jakarta.apache.org"><b>support</b></a> 
+        <b><a href="mailto:taglibs-dev at jakarta.apache.org">development</a>   
+      <a href="mailto:jsr-52-comments at jcp.org">comments to JSR-52</a></b></font></td>
+  </tr>
+</table>
+</body>
+<!-- #EndTemplate --></html>
diff --git a/standard/examples/web/iterators/Collaboration.jsp b/standard/examples/web/iterators/Collaboration.jsp
new file mode 100644
index 0000000..f0d7fce
--- /dev/null
+++ b/standard/examples/web/iterators/Collaboration.jsp
@@ -0,0 +1,42 @@
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<%@ taglib prefix="ex" uri="/jstl-examples-taglib" %>
+
+<html>
+<head>
+  <title>JSTL: Iterator Support 2-- Collaboration Example</title>
+</head>
+<body bgcolor="#FFFFFF">
+<h3>Collaboration</h3>
+
+<h4>Without custom tags</h4>
+
+<table>
+<c:forEach var="customer" items="${customers}" varStatus="status">
+  <tr>
+    <jsp:useBean type="javax.servlet.jsp.jstl.core.LoopTagStatus" id="status"/>
+    <c:choose>
+      <c:when test="<%= status.getCount() % 2 == 1 %>">
+	    <td bgcolor="#FFFF66">
+	  </c:when>
+	  <c:otherwise>
+	    <td bgcolor="#99FFCC">
+	  </c:otherwise>
+    </c:choose>
+    <c:out value="${customer}"/></td>
+  </tr>
+</c:forEach> 
+</table>
+
+<h4>Using custom tags <even> and <odd></h4>
+
+<table>
+<c:forEach var="customer" items="${customers}">
+  <tr>
+    <ex:odd><td bgcolor="#FFFF66"></ex:odd>
+    <ex:even><td bgcolor="#99FFCC"></ex:even>
+    <c:out value="${customer}"/></td>
+  </tr>
+</c:forEach> 
+</table>
+</body>
+</html>
diff --git a/standard/examples/web/iterators/DataTypes.jsp b/standard/examples/web/iterators/DataTypes.jsp
new file mode 100644
index 0000000..3b50705
--- /dev/null
+++ b/standard/examples/web/iterators/DataTypes.jsp
@@ -0,0 +1,40 @@
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+
+<html>
+<head>
+  <title>JSTL: Iterator Support -- Data Types Example</title>
+</head>
+<body bgcolor="#FFFFFF">
+<h3>Data Types</h3>
+
+<h4>Array of primitives (int)</h4>
+
+<c:forEach var="i" items="${intArray}">
+  <c:out value="${i}"/> •
+</c:forEach>
+
+<h4>Array of objects (String)</h4>
+
+<c:forEach var="string" items="${stringArray}">
+  <c:out value="${string}"/><br>
+</c:forEach>
+
+<h4>Enumeration (warning: this only works until enumeration is exhausted!)</h4>
+
+<c:forEach var="item" items="${enumeration}" begin="2" end="10" step="2">
+  <c:out value="${item}"/><br>
+</c:forEach>
+
+<h4>Properties (Map)</h4>
+
+<c:forEach var="prop" items="${numberMap}" begin="1" end="5">
+  <c:out value="${prop.key}"/> = <c:out value="${prop.value}"/><br>
+</c:forEach>
+
+<h4>String (Comma Separated Values)</h4>
+
+<c:forEach var="token" items="bleu,blanc,rouge">
+  <c:out value="${token}"/><br>
+</c:forEach>
+</body>
+</html>
diff --git a/standard/examples/web/iterators/Extensability.jsp b/standard/examples/web/iterators/Extensability.jsp
new file mode 100644
index 0000000..e3ab3c1
--- /dev/null
+++ b/standard/examples/web/iterators/Extensability.jsp
@@ -0,0 +1,45 @@
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<%@ taglib prefix="ex" uri="/jstl-examples-taglib" %>
+
+
+<c:set var="first"><c:out value="${param['first']}" default="1"/></c:set>
+<c:set var="pageSize"><c:out value="${param['pageSize']}" default="30"/></c:set>
+<c:set var="last" value="${first+pageSize-1}"/>
+
+<c:if test="${first != 1}">
+   <c:url var="prevURL" value="Extensability.jsp">
+      <c:param name="first" value="${first - pageSize}"/>
+   </c:url>
+</c:if>
+
+<c:url var="nextURL" value="Extensability.jsp">
+      <c:param name="first" value="${last+1}"/>
+</c:url>
+
+<table><tr><th>#</th></th><th>Code</th><th colspan="2" align="left">Name</th></tr>
+<ex:locales var="locale" varStatus="status" varTotal="total" begin="${first}" end="${last}">
+   <tr>
+      <td><c:out value="${status.index}"/></td>
+      <td><c:out value="${locale}"/></td>
+      <td><c:out value="${locale.displayName}"/></td>
+      <td><ex:defaultLocale><b>(default locale)</b></ex:defaultLocale></td>
+   </tr>
+</ex:locales>
+</table>
+
+<c:if test="${last > total}">
+   <c:set var="last" value="${total}"/>
+   <c:remove var="nextURL"/>
+</c:if>
+
+<br>
+Showing locales <c:out value="${first}"/> to <c:out value="${last}"/> of <c:out value="${total}"/><br>
+<br>
+<c:if test="${not empty prevURL}">
+<a href="<c:out value="${prevURL}"/>">previous</a>   
+</c:if>
+<c:if test="${not empty nextURL}">
+<a href="<c:out value="${nextURL}"/>">next</a>   
+</c:if>
+<br>
+
diff --git a/standard/examples/web/iterators/ForTokens.jsp b/standard/examples/web/iterators/ForTokens.jsp
new file mode 100644
index 0000000..da371a8
--- /dev/null
+++ b/standard/examples/web/iterators/ForTokens.jsp
@@ -0,0 +1,25 @@
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+
+<html>
+<head>
+  <title>JSTL: Iterator Support -- forTokens Example</title>
+</head>
+<body bgcolor="#FFFFFF">
+
+<h3><forTokens></h3>
+
+<h4>String with '|' delimiter</h4>
+
+<c:forTokens var="token" items="bleu,blanc,rouge|vert,jaune|blanc,rouge"
+              delims="|">
+  <c:out value="${token}"/> •
+</c:forTokens>
+
+<h4>String with '|' and ',' delimiters</h4>
+
+<c:forTokens var="token" items="bleu,blanc,rouge|vert,jaune|blanc,rouge"
+              delims="|,">
+  <c:out value="${token}"/> •
+</c:forTokens>
+</body>
+</html>
diff --git a/standard/examples/web/iterators/Simple.jsp b/standard/examples/web/iterators/Simple.jsp
new file mode 100644
index 0000000..932e3e6
--- /dev/null
+++ b/standard/examples/web/iterators/Simple.jsp
@@ -0,0 +1,18 @@
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+
+<html>
+<head>
+  <title>JSTL: Iterator Support -- Simple Iteration Example</title>
+</head>
+
+<body bgcolor="#FFFFFF">
+<h3>Simple Iteration</h3>
+
+<h4>Customer list</h4>
+
+<c:forEach var="customer" items="${customers}">
+  ${customer}<br>
+</c:forEach>
+
+</body>
+</html>
diff --git a/standard/examples/web/iterators/SimpleRange.jsp b/standard/examples/web/iterators/SimpleRange.jsp
new file mode 100644
index 0000000..6cf5804
--- /dev/null
+++ b/standard/examples/web/iterators/SimpleRange.jsp
@@ -0,0 +1,16 @@
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+
+<html>
+<head>
+  <title>JSTL: Iterator Support -- Simple Range Iteration Example</title>
+</head>
+<body bgcolor="#FFFFFF">
+<h3>Simple Range Iteration</h3>
+
+<h4>1 to 10</h4>
+
+<c:forEach var="i" begin="1" end="10">
+  ${i} •
+</c:forEach>
+</body>
+</html>
diff --git a/standard/examples/web/iterators/Status.jsp b/standard/examples/web/iterators/Status.jsp
new file mode 100644
index 0000000..ccd504d
--- /dev/null
+++ b/standard/examples/web/iterators/Status.jsp
@@ -0,0 +1,53 @@
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+
+<html>
+<head>
+  <title>JSTL: Iterator Support -- Iteration Status Example</title>
+</head>
+<body bgcolor="#FFFFFF">
+<h3>Iteration Status</h3>
+
+<h4>Using status information: current, index, count, first, last</h4>
+<table border="1">
+  <tr>
+    <th>index</th>
+    <th>count</th>
+    <th>last name</th>
+    <th>first name</th>
+    <th>first?</th>
+    <th>last?</th>
+  </tr>
+  <c:forEach var="customer" items="${customers}" varStatus="status">
+    <tr>
+      <td><c:out value="${status.index}"/></td>
+      <td><c:out value="${status.count}"/></td>
+      <td><c:out value="${status.current.lastName}"/></td>
+      <td><c:out value="${status.current.firstName}"/></td>
+      <td><c:out value="${status.first}"/></td>
+      <td><c:out value="${status.last}"/></td>
+    </tr>
+    <c:if test="${status.last}">
+      <c:set var="count" value="${status.count}"/>
+    </c:if>  
+  </c:forEach>
+</table>
+<p>There are <c:out value="${count}"/> customers in the list.
+
+<p>
+
+<h4>Iteration using range attributes</h4>
+<c:forEach var="i" begin="100" end="200" step="5" varStatus="status">
+  <c:if test="${status.first}">
+    begin:<c:out value="${status.begin}">begin</c:out>     
+      end:<c:out value="${status.end}">end</c:out>     
+     step:<c:out value="${status.step}">step</c:out><br>
+    sequence: 
+  </c:if>  
+  <c:out value="${i}"/> 
+  <c:if test="${status.last}">
+    <br>There are <c:out value="${status.count}"/> numbers in the list.
+  </c:if>  
+</c:forEach>
+<p>
+</body>
+</html>
diff --git a/standard/examples/web/iterators/index.html b/standard/examples/web/iterators/index.html
new file mode 100644
index 0000000..d837d47
--- /dev/null
+++ b/standard/examples/web/iterators/index.html
@@ -0,0 +1,78 @@
+<html><!-- #BeginTemplate "/Templates/ExamplesTemplate.dwt" -->
+<head>
+<!-- #BeginEditable "doctitle" --> 
+<title>JSTL: Iterator Tags Examples</title>
+<!-- #EndEditable -->
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<link rel="stylesheet" href="../global.css" type="text/css">
+</head>
+
+<body bgcolor="#FFFFFF" text="#000000">
+<table width="100%" border="0" cellpadding="5">
+  <tr> 
+    <td height="0"><font color="#000099"><b>standard taglib • implementation 
+      of the JSP Standard Tag Library • </b></font><font color="#003399"><a href="mailto:taglibs-user at jakarta.apache.org"><b>support</b></a> 
+        <b><a href="mailto:taglibs-dev at jakarta.apache.org">development</a>   
+      <a href="mailto:jsr-52-comments at jcp.org">comments to JSR-52</a></b></font></td>
+  </tr>
+  <tr> 
+    <td bgcolor="#CCCCFF"><font size="-1">Examples     <a href="../index.html">Introduction</a> 
+      • <a href="../elsupport/index.html">General Purpose</a> 
+      • <a href="../conditionals/index.html">Conditionals</a> 
+      • <a href="index.html">Iterators</a> • 
+      <a href="../import/index.jsp">Import</a> • <a href="../format/index.html">I18N 
+      & Formatting</a> • <a href="../xml/index.html">XML</a> 
+      • <a href="../sql/index.jsp">SQL</a> • <a href="../functions/index.html">Functions</a> 
+      • <a href="../tlv/index.html">TLV</a> • <a href="../functions/index.html"></a><a href="../misc/index.html">Misc.</a></font></td>
+  </tr>
+</table>
+<!-- #BeginEditable "body" --> 
+<h2>Iterator Tags Examples</h2>
+<h3>Simple   <a href="../ShowSource.jsp?filename=/iterators/Simple.jsp"><img src="../images/code.gif" width="24" height="24" border="0"></a> 
+  <a href="Simple.jsp"><img src="../images/execute.gif" width="24" height="24" border="0"></a> 
+</h3>
+Simply displays the default <code>toString()</code> value of the items in the 
+<code>Customers</code> collection.<br>
+<h3> Range   <a href="../ShowSource.jsp?filename=/iterators/SimpleRange.jsp"><img src="../images/code.gif" width="24" height="24" border="0"></a> 
+  <a href="SimpleRange.jsp"><img src="../images/execute.gif" width="24" height="24" border="0"></a> 
+</h3>
+<p>Another simple example. Similar to the previous one, except that in this case 
+  there is no collection to iterate over. The <code>items</code> attribute is 
+  optional in the <code><forEach></code> tag. When it is not specified, 
+  the range attributes must be used to iterate a specific number of times over 
+  the tag's body. In this example, we simply iterate over the integer values specified 
+  by the range attributes.</p>
+<h3>Data Types  <a href="../ShowSource.jsp?filename=/iterators/DataTypes.jsp"><img src="../images/code.gif" width="24" height="24" border="0"></a> <a href="DataTypes.jsp"><img src="../images/execute.gif" width="24" height="24" border="0"></a></h3>
+<p>The <code><forEach></code> tag supports a large number of data types 
+  for the collection of objects to iterate over. In this example, we feature the 
+  following data types: array of primitives, array of objects, Enumeration, Properties 
+  (Map), String (Comma Separated Values).</p>
+<h3>Iteration Status  <a href="../ShowSource.jsp?filename=/iterators/Status.jsp"><img src="../images/code.gif" width="24" height="24" border="0"></a> <a href="Status.jsp"><img src="../images/execute.gif" width="24" height="24" border="0"></a></h3>
+<p>The iterator tag exposes a wealth of information relative to the iteration 
+  taking place. This example features some of that status information.</p>
+<h3>Collaboration  <a href="../ShowSource.jsp?filename=/iterators/Collaboration.jsp"><img src="../images/code.gif" width="24" height="24" border="0"></a> <a href="Collaboration.jsp"><img src="../images/execute.gif" width="24" height="24" border="0"></a></h3>
+<p>The iterator tags expose interface IteratorTag to allow custom tags to establish 
+  implicit collaboration. This example shows two custom tags, <even> and 
+  <odd> who take advantage of this implicit collaboration.</p>
+<h3><forTokens>  <a href="../ShowSource.jsp?filename=/iterators/ForTokens.jsp"><img src="../images/code.gif" width="24" height="24" border="0"></a> <a href="ForTokens.jsp"><img src="../images/execute.gif" width="24" height="24" border="0"></a></h3>
+<p>The <forEach> tag provides the basic iteration capabilities. <forTokens> 
+  is a specialization for the handling of Strings of tokens. Essentially the same 
+  as <forEach>, except that it only applies to Strings of tokens and that 
+  it has an extra attribute "delims" to specify the token delimiter.</p>
+<h3>Extensibility  <a href="../ShowSource.jsp?filename=/iterators/Extensability.jsp"><img src="../images/code.gif" width="24" height="24" border="0"></a> <a href="Extensability.jsp"><img src="../images/execute.gif" width="24" height="24" border="0"></a></h3>
+<p>JSTL exposes in its API the abstract class LoopTagSupport to facilitate 
+  the implementation of custom iterator tags that leverage the standard iteration 
+  behavior defined in JSTL. This example shows a custom iterator tag that shows all Locale objects available in the server and a custom conditional sub-tag that
+  display the default locale.</p>
+<!-- #EndEditable -->
+<hr noshade color="#000099">
+<table width="100%" border="0" cellpadding="5">
+  <tr> 
+    <td height="24"><font color="#000099"><b>standard taglib • implementation 
+      of the JSP Standard Tag Library • </b></font><font color="#003399"><a href="mailto:taglibs-user at jakarta.apache.org"><b>support</b></a> 
+        <b><a href="mailto:taglibs-dev at jakarta.apache.org">development</a>   
+      <a href="mailto:jsr-52-comments at jcp.org">comments to JSR-52</a></b></font></td>
+  </tr>
+</table>
+</body>
+<!-- #EndTemplate --></html>
diff --git a/standard/examples/web/misc/IteratorTest.jsp b/standard/examples/web/misc/IteratorTest.jsp
new file mode 100644
index 0000000..3482ba1
--- /dev/null
+++ b/standard/examples/web/misc/IteratorTest.jsp
@@ -0,0 +1,60 @@
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+
+<html>
+<head>
+  <title>JSTL: Miscellaneous -- Various Iterator Tests Example</title>
+</head>
+<body bgcolor="#FFFFFF">
+<h3>Various tests for Iterator tags</h3>
+
+<h4>Iteration with only end specified (no items): end="10"</h4>
+(illegal)
+<%--
+<c:forEach var="i" end="10">
+  <c:out value="${i}"/> • 
+</c:forEach>
+--%>
+
+<h4>Iteration with only begin specified (no items): begin="10"</h4>
+(illegal)
+<%--
+<c:forEach var="i" begin="10">
+  ${i} • 
+</c:forEach>
+--%>
+
+<h4>Iteration with only begin specified (with items): begin="2"</h4>
+
+<c:forEach var="i" items="${customers}" begin="2" varStatus="status">
+  index: ${status.index} • 
+  count: ${status.count} • 
+  item: ${i}<br>
+</c:forEach>
+
+<h4>Iteration with only end specified (with items): end="1"</h4>
+
+<c:forEach var="i" items="${customers}" end="1" varStatus="status">
+  index: ${status.index} • 
+  count: ${status.count} • 
+  item:  ${i}><br>
+</c:forEach>
+
+<h4>Iteration with begin > end</h4>
+<c:catch var="ex">
+  <c:forEach var="i" items="${customers}" begin="3" end="1" varStatus="status">
+    index: ${status.index} • 
+    count: ${status.count} • 
+    item:  ${i}<br>
+  </c:forEach>
+  <c:forTokens var="i" items="one,two,three,four,five" delims="," begin="3" end="1" varStatus="status">
+    index: ${status.index} • 
+    count: ${status.count} • 
+    item:  ${i}<br>
+  </c:forTokens>
+</c:catch>
+<c:if test="${ex != null}">
+  Exception: ${ex}
+</c:if>
+
+</body>
+</html>
diff --git a/standard/examples/web/misc/index.html b/standard/examples/web/misc/index.html
new file mode 100644
index 0000000..aaf7d09
--- /dev/null
+++ b/standard/examples/web/misc/index.html
@@ -0,0 +1,46 @@
+<html><!-- #BeginTemplate "/Templates/ExamplesTemplate.dwt" -->
+<head>
+<!-- #BeginEditable "doctitle" --> 
+<title>JSTL: Miscellaneous Examples</title>
+<!-- #EndEditable -->
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<link rel="stylesheet" href="../global.css" type="text/css">
+</head>
+
+<body bgcolor="#FFFFFF" text="#000000">
+<table width="100%" border="0" cellpadding="5">
+  <tr> 
+    <td height="0"><font color="#000099"><b>standard taglib • implementation 
+      of the JSP Standard Tag Library • </b></font><font color="#003399"><a href="mailto:taglibs-user at jakarta.apache.org"><b>support</b></a> 
+        <b><a href="mailto:taglibs-dev at jakarta.apache.org">development</a>   
+      <a href="mailto:jsr-52-comments at jcp.org">comments to JSR-52</a></b></font></td>
+  </tr>
+  <tr> 
+    <td bgcolor="#CCCCFF"><font size="-1">Examples     <a href="../index.html">Introduction</a> 
+      • <a href="../elsupport/index.html">General Purpose</a> 
+      • <a href="../conditionals/index.html">Conditionals</a> 
+      • <a href="../iterators/index.html">Iterators</a> • 
+      <a href="../import/index.jsp">Import</a> • <a href="../format/index.html">I18N 
+      & Formatting</a> • <a href="../xml/index.html">XML</a> 
+      • <a href="../sql/index.jsp">SQL</a> • <a href="../functions/index.html">Functions</a> 
+      • <a href="../tlv/index.html">TLV</a> • <a href="../functions/index.html"></a><a href="index.html">Misc.</a></font></td>
+  </tr>
+</table>
+<!-- #BeginEditable "body" --> 
+<h2>Miscellaneous</h2>
+<h3>Iterator Tags Tests   <a href="../ShowSource.jsp?filename=/misc/IteratorTest.jsp"><img src="../images/code.gif" width="24" height="24" border="0"></a> 
+  <a href="../misc/IteratorTest.jsp"><img src="../images/execute.gif" width="24" height="24" border="0"></a> 
+</h3>
+Some tests on the iterator tags.<br>
+<!-- #EndEditable -->
+<hr noshade color="#000099">
+<table width="100%" border="0" cellpadding="5">
+  <tr> 
+    <td height="24"><font color="#000099"><b>standard taglib • implementation 
+      of the JSP Standard Tag Library • </b></font><font color="#003399"><a href="mailto:taglibs-user at jakarta.apache.org"><b>support</b></a> 
+        <b><a href="mailto:taglibs-dev at jakarta.apache.org">development</a>   
+      <a href="mailto:jsr-52-comments at jcp.org">comments to JSR-52</a></b></font></td>
+  </tr>
+</table>
+</body>
+<!-- #EndTemplate --></html>
diff --git a/standard/examples/web/sql/DriverSetup.jsp b/standard/examples/web/sql/DriverSetup.jsp
new file mode 100644
index 0000000..421d2f7
--- /dev/null
+++ b/standard/examples/web/sql/DriverSetup.jsp
@@ -0,0 +1,22 @@
+<%@ taglib prefix="sql" uri="http://java.sun.com/jsp/jstl/sql" %>
+
+<html>
+<head>
+  <title>JSTL: SQL action examples</title>
+</head>
+<body bgcolor="#FFFFFF">
+
+<h1>SQL Driver Setup Example</h1>
+
+<code>
+<pre>
+<sql:setDataSource
+  var="example"
+  driver="RmiJdbc.RJDriver"
+  url="jdbc:rmi://localhost:1099/jdbc:cloudscape:CloudscapeDB;create=true"
+/>
+</pre>
+</code>
+
+</body>
+</html>
diff --git a/standard/examples/web/sql/QueryDirect.jsp b/standard/examples/web/sql/QueryDirect.jsp
new file mode 100644
index 0000000..e01db7c
--- /dev/null
+++ b/standard/examples/web/sql/QueryDirect.jsp
@@ -0,0 +1,86 @@
+<%@ taglib prefix="sql" uri="http://java.sun.com/jsp/jstl/sql" %>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+
+<html>
+<head>
+  <title>JSTL: SQL action examples</title>
+</head>
+<body bgcolor="#FFFFFF">
+
+<h1>SQL Direct Query Execution</h1>
+<p>This example demonstrates how the row and columns can be directly accessed using various direct mechanisms.<p>
+
+
+<!-- NOTE: the sql:setDataSource tag is for prototyping and simple applications. You should really use a DataSource object instead --!>
+
+<sql:setDataSource
+  var="example"
+  driver="${sessionScope.myDbDriver}"
+  url="${sessionScope.myDbUrl}"
+  user="${sessionScope.myDbUserName}"
+  password="${sessionScope.myDbPassword}"
+/>
+
+<sql:transaction dataSource="${example}">
+
+  <sql:update var="newTable">
+    create table mytable (
+      nameid int primary key,
+      name varchar(80)
+    )
+  </sql:update>
+
+  <sql:update var="updateCount">
+    INSERT INTO mytable VALUES (1,'Paul Oakenfold')
+  </sql:update>
+  <sql:update var="updateCount">
+    INSERT INTO mytable VALUES (2,'Timo Maas')
+  </sql:update>
+  <sql:update var="updateCount">
+    INSERT INTO mytable VALUES (3,'Paul van Dyk')
+  </sql:update>
+
+  <sql:query var="deejays">
+    SELECT * FROM mytable
+  </sql:query>
+
+</sql:transaction>
+
+<hr>
+
+<h2>Using the Row index and Column name</h2>
+Row[0].NAMEID: <c:out value="${deejays.rows[0].NAMEID}" />
+<br>
+Row[0].NAME: <c:out value="${deejays.rows[0].NAME}" />
+<br>
+Row[1].NAMEID: <c:out value="${deejays.rows[1].NAMEID}" />
+<br>
+Row[1].NAME: <c:out value="${deejays.rows[1].NAME}" />
+<br>
+Row[2].NAMEID: <c:out value="${deejays.rows[2].NAMEID}" />
+<br>
+Row[2].NAME: <c:out value="${deejays.rows[2].NAME}" />
+<br>
+
+<hr>
+
+<h2>Using the Row and Column index</h2>
+Row[0][0]: <c:out value="${deejays.rowsByIndex[0][0]}" />
+<br>
+Row[0][1]: <c:out value="${deejays.rowsByIndex[0][1]}" />
+<br>
+Row[1][0]: <c:out value="${deejays.rowsByIndex[1][0]}" />
+<br>
+Row[1][1]: <c:out value="${deejays.rowsByIndex[1][1]}" />
+<br>
+Row[2][0]: <c:out value="${deejays.rowsByIndex[2][0]}" />
+<br>
+Row[2][1]: <c:out value="${deejays.rowsByIndex[2][1]}" />
+<br>
+
+<sql:update var="newTable" dataSource="${example}">
+  drop table mytable
+</sql:update>
+
+</body>
+</html>
diff --git a/standard/examples/web/sql/QueryIterate.jsp b/standard/examples/web/sql/QueryIterate.jsp
new file mode 100644
index 0000000..e829b1b
--- /dev/null
+++ b/standard/examples/web/sql/QueryIterate.jsp
@@ -0,0 +1,104 @@
+<%@ taglib prefix="sql" uri="http://java.sun.com/jsp/jstl/sql" %>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+
+<html>
+<head>
+  <title>JSTL: SQL action examples</title>
+</head>
+<body bgcolor="#FFFFFF">
+
+<h1>SQL Query Execution using an iterator</h1>
+
+
+<!-- NOTE: the sql:setDataSource tag is for prototyping and simple applications. You should really use a DataSource object instead --!>
+
+<sql:setDataSource
+  var="example"
+  driver="${sessionScope.myDbDriver}"
+  url="${sessionScope.myDbUrl}"
+  user="${sessionScope.myDbUserName}"
+  password="${sessionScope.myDbPassword}"
+/>
+
+<sql:transaction dataSource="${example}">
+
+  <sql:update var="newTable">
+    create table mytable (
+      nameid int primary key,
+      name varchar(80)
+    )
+  </sql:update>
+
+  <sql:update var="updateCount">
+    INSERT INTO mytable VALUES (1,'Paul Oakenfold')
+  </sql:update>
+  <sql:update var="updateCount">
+    INSERT INTO mytable VALUES (2,'Timo Maas')
+  </sql:update>
+  <sql:update var="updateCount">
+    INSERT INTO mytable VALUES (3,'Paul van Dyk')
+  </sql:update>
+
+
+  <sql:query var="deejays">
+    SELECT * FROM mytable
+  </sql:query>
+
+</sql:transaction>
+
+<hr>
+
+<h2>Iterating over each Row of the result</h2>
+
+<table border="1">
+  <c:forEach var="row" items="${deejays.rowsByIndex}">
+    <tr>
+      <c:forEach var="column" items="${row}">
+        <td><c:out value="${column}"/></td>
+      </c:forEach>
+    </tr>
+  </c:forEach>
+</table>
+
+<hr>
+
+<h2>Iterating over Columns without knowing the index</h2>
+
+<table border="1">
+  <c:forEach var="row" items="${deejays.rows}">
+  <tr>
+    <td>Name: <c:out value="${row.NAMEID}"/></td>
+    <td>Value: <c:out value="${row.NAME}"/></td>
+  </tr>
+  </c:forEach>
+</table>
+
+<hr>
+
+<h2>Putting it all together</h2>
+
+<%-- Easiest example showing how to populate a table --%>
+<table border="1">
+  <tr>
+  <%-- Get the column names for the header of the table --%>
+  <c:forEach var="columnName" items="${deejays.columnNames}">
+    <th><c:out value="${columnName}"/></th>
+  </c:forEach>
+
+  <%-- Get the value of each column while iterating over rows --%>
+  <c:forEach var="row" items="${deejays.rowsByIndex}">
+    <tr>
+      <c:forEach var="column" items="${row}">
+        <td><c:out value="${column}"/></td>
+      </c:forEach>
+  </c:forEach>
+</table>
+
+
+<sql:update var="newTable" dataSource="${example}">
+  drop table mytable
+</sql:update>
+
+
+</body>
+</html>
diff --git a/standard/examples/web/sql/QueryParam.jsp b/standard/examples/web/sql/QueryParam.jsp
new file mode 100644
index 0000000..5c1b7f4
--- /dev/null
+++ b/standard/examples/web/sql/QueryParam.jsp
@@ -0,0 +1,72 @@
+<%@ taglib prefix="sql" uri="http://java.sun.com/jsp/jstl/sql" %>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+
+<html>
+<head>
+  <title>JSTL: SQL action examples</title>
+</head>
+<body bgcolor="#FFFFFF">
+
+<% request.setAttribute("newName", new String("Paul van Dyk")); %>
+
+<h1>SQL Query Execution using parameters</h1>
+<p>Using parameter marker's to insert values in the SQL statements</p>
+
+
+
+<!-- NOTE: the sql:setDataSource tag is for prototyping and simple applications. You should really use a DataSource object instead --!>
+
+<sql:setDataSource
+  var="example"
+  driver="${sessionScope.myDbDriver}"
+  url="${sessionScope.myDbUrl}"
+  user="${sessionScope.myDbUserName}"
+  password="${sessionScope.myDbPassword}"
+/>
+
+<sql:transaction dataSource="${example}">
+
+  <sql:update var="newTable">
+    create table mytable (
+      nameid int primary key,
+      name varchar(80)
+    )
+  </sql:update>
+
+  <sql:update var="updateCount">
+    INSERT INTO mytable VALUES (1,'Paul Oakenfold')
+  </sql:update>
+
+  <sql:update var="updateCount">
+    INSERT INTO mytable VALUES (?,'Timo Maas')
+      <sql:param value="2"/>
+  </sql:update>
+
+  <sql:update var="updateCount">
+    INSERT INTO mytable VALUES (?,?)
+      <sql:param value="3"/>
+      <sql:param value="${newName}"/>
+  </sql:update>
+
+  <sql:query var="deejay">
+    SELECT * FROM mytable
+  </sql:query>
+
+</sql:transaction>
+
+<table border="1">
+  <c:forEach var="row" items="${deejay.rows}">
+    <tr>
+      <td><c:out value="${row.NAMEID}"/></td>
+      <td><c:out value="${row.NAME}"/></td>
+    </tr>
+    </c:forEach>
+</table>
+
+<sql:update var="newTable" dataSource="${example}">
+  drop table mytable
+</sql:update>
+
+
+</body>
+</html>
diff --git a/standard/examples/web/sql/Transaction.jsp b/standard/examples/web/sql/Transaction.jsp
new file mode 100644
index 0000000..eaaf8ca
--- /dev/null
+++ b/standard/examples/web/sql/Transaction.jsp
@@ -0,0 +1,60 @@
+<%@ taglib prefix="sql" uri="http://java.sun.com/jsp/jstl/sql" %>
+
+<html>
+<head>
+  <title>JSTL: SQL action examples</title>
+</head>
+<body bgcolor="#FFFFFF">
+
+<h1>SQL Transactions</h1>
+
+
+<!-- NOTE: the sql:setDataSource tag is for prototyping and simple applications. You should really use a DataSource object instead --!>
+
+<sql:setDataSource
+  var="example"
+  driver="${sessionScope.myDbDriver}"
+  url="${sessionScope.myDbUrl}"
+  user="${sessionScope.myDbUserName}"
+  password="${sessionScope.myDbPassword}"
+/>
+
+<p>You can group transactions together using the <sql:transaction> tag.</p>
+
+<h2>Creating table using a transaction</h2>
+
+<sql:transaction dataSource="${example}">
+  <sql:update var="newTable">
+    create table mytable (
+      nameid int primary key,
+      name varchar(80)
+    )
+  </sql:update>
+</sql:transaction>
+
+<p>DONE: Creating table using a transaction</p>
+
+<hr>
+
+<h2>Populating table in one transaction</h2>
+
+<sql:transaction dataSource="${example}">
+  <sql:update var="updateCount">
+    INSERT INTO mytable VALUES (1,'Paul Oakenfold')
+  </sql:update>
+  <sql:update var="updateCount">
+    INSERT INTO mytable VALUES (2,'Timo Maas')
+  </sql:update>
+  <sql:update var="updateCount">
+    INSERT INTO mytable VALUES (3,'Paul van Dyk')
+  </sql:update>
+</sql:transaction>
+
+<p>DONE: Populating table in one transaction</p>
+
+<sql:update var="newTable" dataSource="${example}">
+  drop table mytable
+</sql:update>
+
+</body>
+</html>
diff --git a/standard/examples/web/sql/Update.jsp b/standard/examples/web/sql/Update.jsp
new file mode 100644
index 0000000..2108c67
--- /dev/null
+++ b/standard/examples/web/sql/Update.jsp
@@ -0,0 +1,115 @@
+<%@ taglib prefix="sql" uri="http://java.sun.com/jsp/jstl/sql" %>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+
+<html>
+<head>
+  <title>JSTL: SQL action examples</title>
+</head>
+<body bgcolor="#FFFFFF">
+
+<h1>SQL Update Execution</h1>
+
+
+<!-- NOTE: the sql:setDataSource tag is for prototyping and simple applications. You should really use a DataSource object instead --!>
+
+<sql:setDataSource
+  var="example"
+  driver="${sessionScope.myDbDriver}"
+  url="${sessionScope.myDbUrl}"
+  user="${sessionScope.myDbUserName}"
+  password="${sessionScope.myDbPassword}"
+/>
+
+<hr>
+
+<sql:transaction dataSource="${example}">
+
+  <sql:update var="newTable">
+    create table mytable (
+      nameid int primary key,
+      name varchar(80)
+    )
+  </sql:update>
+
+<h2>Inserting three rows into table</h2>
+  <sql:update var="updateCount">
+    INSERT INTO mytable VALUES (1,'Paul Oakenfold')
+  </sql:update>
+  <sql:update var="updateCount">
+    INSERT INTO mytable VALUES (2,'Timo Maas')
+  </sql:update>
+  <sql:update var="updateCount">
+    INSERT INTO mytable VALUES (3,'Paul van Dyk')
+  </sql:update>
+
+<p>DONE: Inserting three rows into table</p>
+
+
+  <sql:query var="deejays">
+    SELECT * FROM mytable
+  </sql:query>
+
+</sql:transaction>
+
+<%-- An example showing how to populate a table --%>
+<table border="1">
+  <%-- Get the column names for the header of the table --%>
+  <c:forEach var="columnName" items="${deejays.columnNames}">
+    <th><c:out value="${columnName}"/></th>
+  </c:forEach>
+
+  <%-- Get the value of each column while iterating over rows --%>
+  <c:forEach var="row" items="${deejays.rows}">
+    <tr>
+    <c:forEach var="column" items="${row}">
+      <td><c:out value="${column.value}"/></td>
+    </c:forEach>
+  </tr>
+  </c:forEach>
+</table>
+
+
+<h2>Deleting second row from table</h2>
+
+  <sql:update var="updateCount" dataSource="${example}">
+    DELETE FROM mytable WHERE nameid=2
+  </sql:update>
+
+<p>DONE: Deleting second row from table</p>
+
+<sql:query var="deejays" dataSource="${example}">
+  SELECT * FROM mytable
+</sql:query>
+
+
+<%-- Yet another example showing how to populate a table --%>
+<table border="1">
+  <c:forEach var="row" items="${deejays.rows}" varStatus="status">
+    <%-- Get the column names for the header of the table --%>
+    <c:choose>
+      <c:when test="${status.count == 1}">
+        <%-- Each row is a Map object key'd by the column name --%>
+        <tr>
+        <c:forEach var="metaData" items="${row}">
+          <th><c:out value="${metaData.key}"/></th>
+        </c:forEach>
+        </tr>
+      </c:when>
+    </c:choose>
+    <tr>
+    <c:forEach var="column" items="${row}">
+      <%-- Get the value of each column while iterating over rows --%>
+      <td><c:out value="${column.value}"/></td>
+    </c:forEach>
+  </tr>
+  </c:forEach>
+</table>
+
+
+<sql:update var="newTable" dataSource="${example}">
+  drop table mytable
+</sql:update>
+
+
+</body>
+</html>
diff --git a/standard/examples/web/sql/index.jsp b/standard/examples/web/sql/index.jsp
new file mode 100644
index 0000000..59a100f
--- /dev/null
+++ b/standard/examples/web/sql/index.jsp
@@ -0,0 +1,100 @@
+<html><!-- #BeginTemplate "/Templates/ExamplesTemplate.dwt" -->
+<head>
+<!-- #BeginEditable "doctitle" --> 
+<title>Untitled Document</title>
+<!-- #EndEditable -->
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<link rel="stylesheet" href="../global.css" type="text/css">
+</head>
+
+<body bgcolor="#FFFFFF" text="#000000">
+<table width="100%" border="0" cellpadding="5">
+  <tr> 
+    <td height="0"><font color="#000099"><b>standard taglib • implementation 
+      of the JSP Standard Tag Library • </b></font><font color="#003399"><a href="mailto:taglibs-user at jakarta.apache.org"><b>support</b></a> 
+        <b><a href="mailto:taglibs-dev at jakarta.apache.org">development</a>   
+      <a href="mailto:jsr-52-comments at jcp.org">comments to JSR-52</a></b></font></td>
+  </tr>
+  <tr> 
+    <td bgcolor="#CCCCFF"><font size="-1">Examples     <a href="../index.html">Introduction</a> 
+      • <a href="../elsupport/index.html">General Purpose</a> 
+      • <a href="../conditionals/index.html">Conditionals</a> 
+      • <a href="../iterators/index.html">Iterators</a> • 
+      <a href="../import/index.jsp">Import</a> • <a href="../format/index.html">I18N 
+      & Formatting</a> • <a href="../xml/index.html">XML</a> 
+      • <a href="index.jsp">SQL</a> • <a href="../functions/index.html">Functions</a> 
+      • <a href="../tlv/index.html">TLV</a> • <a href="../functions/index.html"></a><a href="../misc/index.html">Misc.</a></font></td>
+  </tr>
+</table>
+<!-- #BeginEditable "body" --> 
+<h1>SQL Tags Examples</h1>
+<p>These examples create their own table for demonstration purposes. Every database 
+  supports table creation in a slightly different way. For instance, different 
+  databases have different types and constraints. The simplest possible table 
+  was chosen, however it may still not be supported by your particular database. 
+  Check your database documentation or administrator if you have problems creating 
+  the table and modify the examples acordingly. Here is the table used in the 
+  examples:</p>
+<pre><code>
+    create table mytable (
+      nameid int primary key,
+      name varchar(80)
+    )
+</code></pre>
+<p>Enter your Driver Name and DataBase URL to test the Database Tag Library.</p>
+<p>NOTE: You will need to have the DataBase Driver classes available to your server's 
+  classloader or in your server's CLASSPATH at startup.</p>
+<form name="myform" action="session.jsp" method="post" >
+  <table width="100%" border="0" cellspacing="0" cellpadding="0">
+    <tr> 
+      <td>Driver:</td>
+      <td> 
+        <input type="text" size="40" name="dbDriver" value="RmiJdbc.RJDriver">
+      </td>
+    </tr>
+    <tr> 
+      <td>URL:</td>
+      <td> 
+        <input type="text" size="40" name="dbUrl" value="jdbc:rmi://localhost:1099/jdbc:cloudscape:CloudscapeDB;create=true">
+      </td>
+    </tr>
+    <tr> 
+      <td colspan="2"> <br>
+        <p>The following two fields are <strong>Optional</strong>. They are included 
+          for convenience.<br>
+          NOTE: an unsecure <code>form</code> is used.</p>
+      </td>
+    </tr>
+    <tr> 
+      <td>User Name:</td>
+      <td> 
+        <input type="text" size="40" name="dbUserName" value="">
+      </td>
+    </tr>
+    <tr> 
+      <td>Password:</td>
+      <td> 
+        <input type="password" size="40" name="dbPassword" value="">
+      </td>
+    </tr>
+  </table>
+  <p> 
+    <input type="submit" name="Submit" value="Submit">
+  </p>
+</form>
+<hr>
+<p>NOTE: You can access the tags directly here to look at the source. If you do 
+  not provide a valid Driver and URL using the above form, the tags will NOT run properly.</p>
+<%@ include file="links.html" %>
+<!-- #EndEditable -->
+<hr noshade color="#000099">
+<table width="100%" border="0" cellpadding="5">
+  <tr> 
+    <td height="24"><font color="#000099"><b>standard taglib • implementation 
+      of the JSP Standard Tag Library • </b></font><font color="#003399"><a href="mailto:taglibs-user at jakarta.apache.org"><b>support</b></a> 
+        <b><a href="mailto:taglibs-dev at jakarta.apache.org">development</a>   
+      <a href="mailto:jsr-52-comments at jcp.org">comments to JSR-52</a></b></font></td>
+  </tr>
+</table>
+</body>
+<!-- #EndTemplate --></html>
diff --git a/standard/examples/web/sql/links.html b/standard/examples/web/sql/links.html
new file mode 100644
index 0000000..8194ba4
--- /dev/null
+++ b/standard/examples/web/sql/links.html
@@ -0,0 +1,32 @@
+<h2>DataBase Tags Examples</h2>
+
+<h3>Query Iterate   <a href="../ShowSource.jsp?filename=/sql/QueryIterate.jsp"><img src="../images/code.gif" width="24" height="24" border="0"></a> 
+  <a href="../sql/QueryIterate.jsp"><img src="../images/execute.gif" width="24" height="24" border="0"></a> 
+</h3>
+Example showing how to iterate over the result of a query.<br>
+
+<h3>Update   <a href="../ShowSource.jsp?filename=/sql/Update.jsp"><img src="../images/code.gif" width="24" height="24" border="0"></a> 
+  <a href="../sql/Update.jsp"><img src="../images/execute.gif" width="24" height="24" border="0"></a> 
+</h3>
+Example showing several database updates.<br>
+
+<h3>Direct Query   <a href="../ShowSource.jsp?filename=/sql/QueryDirect.jsp"><img src="../images/code.gif" width="24" height="24" border="0"></a> 
+  <a href="../sql/QueryDirect.jsp"><img src="../images/execute.gif" width="24" height="24" border="0"></a> 
+</h3>
+Example showing how the the result of a query can be directly accessed.<br>
+
+<h3>Query Parameters   <a href="../ShowSource.jsp?filename=/sql/QueryParam.jsp"><img src="../images/code.gif" width="24" height="24" border="0"></a> 
+  <a href="../sql/QueryParam.jsp"><img src="../images/execute.gif" width="24" height="24" border="0"></a> 
+</h3>
+Example showing how query parameters can be used to create an SQL query.<br>
+
+<h3>Transaction   <a href="../ShowSource.jsp?filename=/sql/Transaction.jsp"><img src="../images/code.gif" width="24" height="24" border="0"></a> 
+  <a href="../sql/Transaction.jsp"><img src="../images/execute.gif" width="24" height="24" border="0"></a> 
+</h3>
+Example showing how to setup transactions.<br>
+
+<h3>Driver Setup   <a href="../ShowSource.jsp?filename=/sql/DriverSetup.jsp"><img src="../images/code.gif" width="24" height="24" border="0"></a> 
+  <a href="../sql/DriverSetup.jsp"><img src="../images/execute.gif" width="24" height="24" border="0"></a> 
+</h3>
+A sample page showing how a driver can be configured. NOTE: this is meant for prototyping and simple applications.<br>
+
diff --git a/standard/examples/web/sql/session.jsp b/standard/examples/web/sql/session.jsp
new file mode 100644
index 0000000..7f41762
--- /dev/null
+++ b/standard/examples/web/sql/session.jsp
@@ -0,0 +1,17 @@
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+
+<html>
+<head>
+   <title>Jakarta DBTAGS Taglib Example</title>
+</head>
+<body bgcolor="white">
+
+<c:set var="myDbUrl" value="${param.dbUrl}" scope="session"/>
+<c:set var="myDbDriver" value="${param.dbDriver}" scope="session"/>
+<c:set var="myDbUserName" value="${param.dbUserName}" scope="session"/>
+<c:set var="myDbPassword" value="${param.dbPassword}" scope="session"/>
+
+<%@ include file="links.html" %>
+
+</body>
+</html>
diff --git a/standard/examples/web/tlv/PermittedTaglibsError.jsp b/standard/examples/web/tlv/PermittedTaglibsError.jsp
new file mode 100644
index 0000000..d19be40
--- /dev/null
+++ b/standard/examples/web/tlv/PermittedTaglibsError.jsp
@@ -0,0 +1,26 @@
+<%@ taglib prefix="permittedTaglibs" uri="http://jakarta.apache.org/taglibs/standard/permittedTaglibs" %>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<%@ taglib prefix="ex" uri="/jstl-examples-taglib" %>
+
+<html>
+<head>
+  <title>JSTL: Tag Library Validator -- PermittedTaglibs Error</title>
+</head>
+<body bgcolor="#FFFFFF">
+
+<h3>This JSP page uses taglibs that are not permitted. A translation error will occur.</h3>
+
+<h4>Using custom tags <even> and <odd></h4>
+
+<table>
+<c:forEach var="customer" items="${customers}">
+  <tr>
+    <ex:odd><td bgcolor="#FFFF66"></ex:odd>
+    <ex:even><td bgcolor="#99FFCC"></ex:even>
+    <c:out value="${customer}"/></td>
+  </tr>
+</c:forEach> 
+</table>
+
+</body>
+</html>
diff --git a/standard/examples/web/tlv/PermittedTaglibsOk.jsp b/standard/examples/web/tlv/PermittedTaglibsOk.jsp
new file mode 100644
index 0000000..ca9df81
--- /dev/null
+++ b/standard/examples/web/tlv/PermittedTaglibsOk.jsp
@@ -0,0 +1,30 @@
+<%@ taglib prefix="permittedTaglibs" uri="http://jakarta.apache.org/taglibs/standard/permittedTaglibs" %>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+
+<html>
+<head>
+  <title>JSTL: Tag Library Validator -- ScriptFree OK</title>
+</head>
+<body bgcolor="#FFFFFF">
+
+<h3>This JSP page only uses permitted taglibs (which in this case are the JSTL taglibs)</h3>
+
+<table>
+<c:forEach var="customer" items="${customers}" varStatus="status">
+  <tr>
+    <jsp:useBean type="javax.servlet.jsp.jstl.core.LoopTagStatus" id="status"/>
+    <c:choose>
+      <c:when test="${status.count % 2 == 1}">
+	    <td bgcolor="#FFFF66">
+	  </c:when>
+	  <c:otherwise>
+	    <td bgcolor="#99FFCC">
+	  </c:otherwise>
+    </c:choose>
+    <c:out value="${customer}"/></td>
+  </tr>
+</c:forEach> 
+</table>
+
+</body>
+</html>
diff --git a/standard/examples/web/tlv/ScriptFreeError.jsp b/standard/examples/web/tlv/ScriptFreeError.jsp
new file mode 100644
index 0000000..b5cff51
--- /dev/null
+++ b/standard/examples/web/tlv/ScriptFreeError.jsp
@@ -0,0 +1,15 @@
+<%@ taglib prefix="scriptfree" uri="http://jakarta.apache.org/taglibs/standard/scriptfree" %>
+<html>
+<head>
+  <title>JSTL: Tag Library Validator -- ScriptFree Error</title>
+</head>
+<body bgcolor="#FFFFFF">
+
+<h3>This JSP page is NOT free of scripting elements. Translation error will occur.</h3>
+
+<% java.util.Date date = new java.util.Date(); %>
+
+Date is: <%= date %>
+
+</body>
+</html>
diff --git a/standard/examples/web/tlv/ScriptFreeOk.jsp b/standard/examples/web/tlv/ScriptFreeOk.jsp
new file mode 100644
index 0000000..5152f1d
--- /dev/null
+++ b/standard/examples/web/tlv/ScriptFreeOk.jsp
@@ -0,0 +1,25 @@
+<%@ taglib prefix="scriptfree" uri="http://jakarta.apache.org/taglibs/standard/scriptfree" %>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<html>
+<head>
+  <title>JSTL: Tag Library Validator -- ScriptFree OK</title>
+</head>
+<body bgcolor="#FFFFFF">
+
+<h3>This JSP page is free of scripting elements</h3>
+
+<table border="1">
+  <c:forEach var="customer" items="${customers}">
+    <tr>
+	  <td><c:out value="${customer.lastName}"/></td>
+	  <td><c:out value="${customer.phoneHome}" default="no home phone specified"/></td>
+	  <td>
+	    <c:out value="${customer.phoneCell}" escapeXml="false">
+		  <font color="red">no cell phone specified</font>
+		</c:out>
+      </td>
+    </tr>
+  </c:forEach>
+</table>
+</body>
+</html>
diff --git a/standard/examples/web/tlv/index.html b/standard/examples/web/tlv/index.html
new file mode 100644
index 0000000..a889031
--- /dev/null
+++ b/standard/examples/web/tlv/index.html
@@ -0,0 +1,67 @@
+<html><!-- #BeginTemplate "/Templates/ExamplesTemplate.dwt" -->
+<head>
+<!-- #BeginEditable "doctitle" --> 
+<title>Tag Library Validators Examples</title>
+<!-- #EndEditable -->
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<link rel="stylesheet" href="../global.css" type="text/css">
+</head>
+
+<body bgcolor="#FFFFFF" text="#000000">
+<table width="100%" border="0" cellpadding="5">
+  <tr> 
+    <td height="0"><font color="#000099"><b>standard taglib • implementation 
+      of the JSP Standard Tag Library • </b></font><font color="#003399"><a href="mailto:taglibs-user at jakarta.apache.org"><b>support</b></a> 
+        <b><a href="mailto:taglibs-dev at jakarta.apache.org">development</a>   
+      <a href="mailto:jsr-52-comments at jcp.org">comments to JSR-52</a></b></font></td>
+  </tr>
+  <tr> 
+    <td bgcolor="#CCCCFF"><font size="-1">Examples     <a href="../index.html">Introduction</a> 
+      • <a href="../elsupport/index.html">General Purpose</a> 
+      • <a href="../conditionals/index.html">Conditionals</a> 
+      • <a href="../iterators/index.html">Iterators</a> • 
+      <a href="../import/index.jsp">Import</a> • <a href="../format/index.html">I18N 
+      & Formatting</a> • <a href="../xml/index.html">XML</a> 
+      • <a href="../sql/index.jsp">SQL</a> • <a href="../functions/index.html">Functions</a> 
+      • <a href="index.html">TLV</a> • <a href="../functions/index.html"></a><a href="../misc/index.html">Misc.</a></font></td>
+  </tr>
+</table>
+<!-- #BeginEditable "body" --> 
+<h2>Tag Library Validators Examples</h2>
+<h3>ScriptFree OK   <a href="../ShowSource.jsp?filename=/tlv/ScriptFreeOk.jsp"><img src="../images/code.gif" width="24" height="24" border="0"></a> 
+  <a href="../tlv/ScriptFreeOk.jsp"><img src="../images/execute.gif" width="24" height="24" border="0"></a> 
+</h3>
+<p>This example shows a JSP page using the ScriptFree TLV. Because this page does 
+  not use any scripting element, there are no translation errors and the page 
+  is properly processed.</p>
+<h3>ScriptFree Error   <a href="../ShowSource.jsp?filename=/tlv/ScriptFreeError.jsp"><img src="../images/code.gif" width="24" height="24" border="0"></a> 
+  <a href="../tlv/ScriptFreeError.jsp"><img src="../images/execute.gif" width="24" height="24" border="0"></a> 
+</h3>
+<p>This example shows a JSP page using the ScriptFree TLV. Because this page uses 
+  scripting elements, a translation error is reported when accessing the page.</p>
+<h3>PermittedTaglibs OK   <a href="../ShowSource.jsp?filename=/tlv/PermittedTaglibsOk.jsp"><img src="../images/code.gif" width="24" height="24" border="0"></a> 
+  <a href="../tlv/PermittedTaglibsOk.jsp"><img src="../images/execute.gif" width="24" height="24" border="0"></a> 
+</h3>
+<p>This example shows a JSP page using the PermittedTaglibs TLV. Because this 
+  page only uses permitted tag libraries, there are no translation errors and 
+  the page is properly processed.</p>
+<h3></h3>
+<h3>PermittedTaglibs Error   <a
+href="../ShowSource.jsp?filename=/tlv/PermittedTaglibsError.jsp"><img src="../images/code.gif" width="24" height="24" border="0"></a> 
+  <a href="../tlv/PermittedTaglibsError.jsp"><img src="../images/execute.gif" width="24" height="24" border="0"></a> 
+</h3>
+<p>This example shows a JSP page using the PermittedTaglibs TLV. Because this 
+  page uses tag libraries that are not allowed, a translation error is reported 
+  when accessing the page.</p>
+<!-- #EndEditable -->
+<hr noshade color="#000099">
+<table width="100%" border="0" cellpadding="5">
+  <tr> 
+    <td height="24"><font color="#000099"><b>standard taglib • implementation 
+      of the JSP Standard Tag Library • </b></font><font color="#003399"><a href="mailto:taglibs-user at jakarta.apache.org"><b>support</b></a> 
+        <b><a href="mailto:taglibs-dev at jakarta.apache.org">development</a>   
+      <a href="mailto:jsr-52-comments at jcp.org">comments to JSR-52</a></b></font></td>
+  </tr>
+</table>
+</body>
+<!-- #EndTemplate --></html>
diff --git a/standard/examples/web/xml/Filter.jsp b/standard/examples/web/xml/Filter.jsp
new file mode 100644
index 0000000..0109ab2
--- /dev/null
+++ b/standard/examples/web/xml/Filter.jsp
@@ -0,0 +1,33 @@
+<%@ taglib prefix="x" uri="http://java.sun.com/jsp/jstl/xml" %>
+<%@ taglib prefix="ex" uri="/jstl-examples-taglib" %>
+
+<html>
+<head>
+  <title>JSTL: XML Support -- Parse / Filter / Out</title>
+</head>
+<body bgcolor="#FFFFFF">
+<h3>Parse / Filter / Out</h3>
+
+<ex:SPath var="spath" select="//a"/>
+<x:parse var="a" filter="${spath}">
+ <nope>
+  <a>
+   <b>
+    <c>
+     foo
+    </c>
+   </b>
+   <d>
+     bar
+   </d>
+  </a>
+ </nope>
+</x:parse>
+
+<x:out select="$a//c"/>
+<x:out select="$a/a/d"/>
+
+<hr />
+
+</body>
+</html>
diff --git a/standard/examples/web/xml/ForEach.jsp b/standard/examples/web/xml/ForEach.jsp
new file mode 100644
index 0000000..0a0dbce
--- /dev/null
+++ b/standard/examples/web/xml/ForEach.jsp
@@ -0,0 +1,83 @@
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<%@ taglib prefix="x" uri="http://java.sun.com/jsp/jstl/xml" %>
+
+<html>
+<head>
+  <title>JSTL: XML Support -- Parse / ForEach</title>
+</head>
+
+<body bgcolor="#FFFFFF">
+
+<h3><x:parse> / <x:forEach></h3>
+
+<c:import var="docString" url="ForEachDoc.xml"/>
+
+<x:parse var="document" doc="${docString}"/>
+
+<table border=1>
+  <tr>
+    <td valign="top"><pre><c:out value="${docString}"/></pre></td>
+    <td valign="top">
+      <table border=1>
+        <tr>
+          <th>Expression</th>
+          <th>Result</th>
+        </tr>
+        <tr>
+          <td><pre>
+<x:forEach select="$document//a" varStatus="status">
+  ${status.index}:  <x:out select="."/> <br>
+<x:forEach>
+</pre>
+          </td>
+          <td>
+<x:forEach select="$document//a" varStatus="status">
+  ${status.index}:  <x:out select="."/>
+  <br />
+</x:forEach>
+</td>
+        </tr>
+
+        <tr>
+          <td><pre>
+<x:forEach select="$document//a" begin="1" end="2" varStatus="status">
+  -> <x:out select="."/> <br>
+<x:forEach>
+</pre>
+          </td>
+          <td>
+<x:forEach select="$document//a" begin="1" end="2" varStatus="status">
+  ${status.index}: <x:out select="."/>
+  <br />
+</x:forEach>
+</td>
+        </tr>
+        
+        <tr>
+          <td><pre>
+<x:forEach select="$document//a" varStatus="status">
+  ${status.index}:  
+  <x:if select=".//d">
+    <d> element present
+  <x:if>
+  <br>
+<x:forEach>
+</pre>
+          </td>
+          <td>
+<x:forEach select="$document//a" varStatus="status">
+  ${status.index}:  
+  <x:if select=".//d">
+    <d> element present
+  </x:if>
+  <br />
+</x:forEach>
+</td>
+        </tr>      
+      </table>
+    </td>
+  </tr>
+</table>
+
+</body>
+</html>
diff --git a/standard/examples/web/xml/ForEachDoc.xml b/standard/examples/web/xml/ForEachDoc.xml
new file mode 100644
index 0000000..a09583d
--- /dev/null
+++ b/standard/examples/web/xml/ForEachDoc.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<doc>
+ <a>
+  <b foo="foo">foo 1</b>
+ </a>
+ <a>
+  <c foo="bar">bar 2</c>
+ </a>
+ <a>
+  <d foo="bar">bar 3</d>
+ </a>
+ <a>
+  <d foo="foo">foo 4</d>
+ </a>
+</doc>
\ No newline at end of file
diff --git a/standard/examples/web/xml/If.jsp b/standard/examples/web/xml/If.jsp
new file mode 100644
index 0000000..149f779
--- /dev/null
+++ b/standard/examples/web/xml/If.jsp
@@ -0,0 +1,42 @@
+<%@ taglib prefix="x" uri="http://java.sun.com/jsp/jstl/xml" %>
+
+<html>
+<head>
+  <title>JSTL: XML Support -- Parse / If</title>
+</head>
+<body bgcolor="#FFFFFF">
+<h3>Parse / If</h3>
+
+<x:parse var="a">
+  <a>
+   <b>
+    <c>
+     foo
+    </c>
+   </b>
+   <d>
+     bar
+   </d>
+  </a>
+</x:parse>
+
+<x:if select="$a//c">
+  $a//c exists
+</x:if>
+
+<br />
+
+<x:if select="$a/a/d">
+  $a/a/d exists
+</x:if>
+
+<br />
+
+<x:if select="$a/w/o/l">
+  $a/w/o/l exists
+</x:if>
+
+<hr />
+
+</body>
+</html>
diff --git a/standard/examples/web/xml/Out.jsp b/standard/examples/web/xml/Out.jsp
new file mode 100644
index 0000000..dca3a8a
--- /dev/null
+++ b/standard/examples/web/xml/Out.jsp
@@ -0,0 +1,66 @@
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<%@ taglib prefix="x" uri="http://java.sun.com/jsp/jstl/xml" %>
+
+<html>
+<head>
+  <title>JSTL: XML Support -- Parse / Out</title>
+</head>
+
+<body bgcolor="#FFFFFF">
+
+<h3><x:parse> / <x:out></h3>
+
+<c:import var="docString" url="games.xml"/>
+
+<x:parse var="doc" doc="${docString}"/>
+
+<table border=1>
+  <tr>
+    <td valign="top"><pre><c:out value="${docString}"/></pre></td>
+    <td valign="top">
+      <table border=1>
+        <tr>
+          <th>Expression</th>
+          <th>Result</th>
+        </tr>
+<%--
+        <tr>
+          <td>3 + 3</td>
+          <td><pre><x:out select="3 + 3"/></pre></td>
+        </tr>
+--%>
+        <tr>
+          <td>$doc//sport</td>
+          <td><pre><x:out select="$doc//sport"/></pre></td>
+        </tr>
+        <tr>
+          <td>$doc/games/country/*</td>
+          <td><pre><x:out select="$doc/games/country/*"/></pre></td>
+        </tr>
+        <tr>
+          <td>$doc//*</td>
+          <td><pre><x:out select="$doc//*"/></pre></td>
+        </tr>
+        <tr>
+          <td>$doc/games/country</td>
+          <td><pre><x:out select="$doc/games/country"/></pre></td>
+        </tr>
+        <tr>
+          <td>$doc/games/country[last()]</td>
+          <td><pre><x:out select="$doc/games/country[last()]"/></pre></td>
+        </tr>
+        <tr>
+          <td>$doc//@id</td>
+          <td><pre><x:out select="$doc//@id"/></pre></td>
+        </tr>
+        <tr>
+          <td>$doc//country[@id='Denmark']</td>
+          <td><pre><x:out select="$doc//country[@id='Denmark']"/></pre></td>
+        </tr>
+      </table>
+    </td>
+  </tr>
+</table>
+
+</body>
+</html>
diff --git a/standard/examples/web/xml/Parse.jsp b/standard/examples/web/xml/Parse.jsp
new file mode 100644
index 0000000..2be8487
--- /dev/null
+++ b/standard/examples/web/xml/Parse.jsp
@@ -0,0 +1,30 @@
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<%@ taglib prefix="x" uri="http://java.sun.com/jsp/jstl/xml" %>
+
+<html>
+<head>
+  <title>JSTL: XML Support -- Parse</title>
+</head>
+<body bgcolor="#FFFFFF">
+<h3>Parse from Objects and URLs</h3>
+
+<c:set var="xmlText">
+  <a>
+   <b>
+    <c>
+     foo
+    </c>
+   </b>
+   <d>
+     bar
+   </d>
+  </a>
+</c:set>    
+
+<x:parse var="a" doc="${xmlText}" />
+
+<x:out select="$a//c"/>
+<x:out select="$a/a/d"/>
+
+</body>
+</html>
diff --git a/standard/examples/web/xml/ParseWithEntities.jsp b/standard/examples/web/xml/ParseWithEntities.jsp
new file mode 100644
index 0000000..f3025a3
--- /dev/null
+++ b/standard/examples/web/xml/ParseWithEntities.jsp
@@ -0,0 +1,27 @@
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<%@ taglib prefix="x" uri="http://java.sun.com/jsp/jstl/xml" %>
+
+<html>
+<head>
+  <title>JSTL: XML Support -- Parse</title>
+</head>
+<body bgcolor="#FFFFFF">
+<h3>Parse from Objects and URLs</h3>
+
+<c:set var="xmlText">
+<?xml version="1.0"?>
+
+<!DOCTYPE project [
+    <!ENTITY included SYSTEM "included.xml">
+]>
+<root>
+  &included;
+</root>
+</c:set>    
+
+<x:parse var="a" doc="${xmlText}" systemId="foo.xml"/>
+
+<x:out select="$a//*"/>
+
+</body>
+</html>
diff --git a/standard/examples/web/xml/Set.jsp b/standard/examples/web/xml/Set.jsp
new file mode 100644
index 0000000..37d4bc0
--- /dev/null
+++ b/standard/examples/web/xml/Set.jsp
@@ -0,0 +1,31 @@
+<%@ taglib prefix="x" uri="http://java.sun.com/jsp/jstl/xml" %>
+
+<html>
+<head>
+  <title>JSTL: XML Support -- Parse / Set / Out</title>
+</head>
+<body bgcolor="#FFFFFF">
+<h3>Parse / Set / Out</h3>
+
+<x:parse var="a">
+  <a>
+   <b>
+    <c>
+     foo
+    </c>
+   </b>
+   <d>
+     <e>
+       bar
+     </e>
+   </d>
+  </a>
+</x:parse>
+
+<x:set var="d" select="$a//d"/>
+<x:out select="$d/e"/>
+
+<hr />
+
+</body>
+</html>
diff --git a/standard/examples/web/xml/Transform.jsp b/standard/examples/web/xml/Transform.jsp
new file mode 100644
index 0000000..804b1d7
--- /dev/null
+++ b/standard/examples/web/xml/Transform.jsp
@@ -0,0 +1,58 @@
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<%@ taglib prefix="x" uri="http://java.sun.com/jsp/jstl/xml" %>
+
+<html>
+<head>
+  <title>JSTL: XML Support -- Transform</title>
+</head>
+<body bgcolor="#FFFFFF">
+<h3>Parse / Expr</h3>
+
+<c:set var="xml">
+  <a><b>header!</b></a>
+</c:set>
+
+<c:set var="xsl">
+  <?xml version="1.0"?>
+  <xsl:stylesheet
+    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
+
+  <xsl:template match="text()">
+    <h1><xsl:value-of select="."/></h1>
+  </xsl:template>
+
+  </xsl:stylesheet>
+</c:set>
+
+Prints "header" as a header:<br />
+<x:transform doc="${xml}" xslt="${xsl}"/>
+
+<hr />
+
+Prints "header" in normal size:<br />
+<x:transform doc="${xml}" xslt="${xsl}" var="doc"/>
+<x:out select="$doc//h1"/>
+
+<hr size="5" />
+
+<hr />
+<h3>Transformations using output from XPath expressions</h3>
+
+<x:parse var="xml" doc="${xml}" />
+<x:set var="miniDoc" select="$xml//b" />
+<x:transform xslt="${xsl}" doc="${miniDoc}" />
+<hr />
+
+<h3>Inline transformations</h3>
+
+<x:transform xslt="${xsl}">
+  <a>
+   <b>
+    <c>Paragraph one!</c>
+    <c>Paragraph foo!</c>
+   </b>
+  </a>
+</x:transform>
+
+</body>
+</html>
diff --git a/standard/examples/web/xml/TransformWithInclusion.jsp b/standard/examples/web/xml/TransformWithInclusion.jsp
new file mode 100644
index 0000000..d11a80a
--- /dev/null
+++ b/standard/examples/web/xml/TransformWithInclusion.jsp
@@ -0,0 +1,32 @@
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<%@ taglib prefix="x" uri="http://java.sun.com/jsp/jstl/xml" %>
+
+<html>
+<head>
+  <title>JSTL: XML Support -- Transform</title>
+</head>
+<body bgcolor="#FFFFFF">
+<h3>Parse / Expr</h3>
+
+<c:set var="xml">
+<?xml version="1.0"?>
+
+<!DOCTYPE project [
+    <!ENTITY included SYSTEM "included.xml">
+]>
+<root>
+  &included;
+</root>
+</c:set>
+
+<c:set var="xsl">
+  <?xml version="1.0"?>
+  <xsl:stylesheet
+    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
+
+  <xsl:import href="/xml/includedStylesheet.xsl" />
+
+  </xsl:stylesheet>
+</c:set>
+
+<x:transform doc="${xml}" docSystemId="foo.xml" xslt="${xsl}"/>
diff --git a/standard/examples/web/xml/When.jsp b/standard/examples/web/xml/When.jsp
new file mode 100644
index 0000000..1377e15
--- /dev/null
+++ b/standard/examples/web/xml/When.jsp
@@ -0,0 +1,68 @@
+<%@ taglib prefix="x" uri="http://java.sun.com/jsp/jstl/xml" %>
+
+<html>
+<head>
+  <title>JSTL: XML Support -- Parse / When</title>
+</head>
+<body bgcolor="#FFFFFF">
+<h3>Parse / When</h3>
+
+<x:parse var="a">
+  <a>
+   <b>
+    <c foo="bar">
+     foo
+    </c>
+   </b>
+   <d>
+     bar
+   </d>
+  </a>
+</x:parse>
+
+<x:choose>
+  <x:when select='$a//c[@foo="bar"]'>
+    @foo = bar
+  </x:when>
+  <x:when select='$a//c[@foo="foo"]'>
+    @foo = foo
+  </x:when>
+  <x:otherwise>
+    @foo not recognized
+  </x:otherwise>
+</x:choose>
+
+<br />
+
+<x:choose>
+  <x:when select='$a//c[@foo="foo"]'>
+    @foo = foo
+  </x:when>
+  <x:when select='$a//c[@foo="bar"]'>
+    @foo = bar
+  </x:when>
+  <x:otherwise>
+    @foo not recognized
+  </x:otherwise>
+</x:choose>
+
+<br />
+
+<x:choose>
+  <x:when select='$a//c[@foo="barr"]'>
+    @foo = barr
+  </x:when>
+  <x:when select='$a//c[@foo="fooo"]'>
+    @foo = fooo
+  </x:when>
+  <x:otherwise>
+    @foo not recognized
+  </x:otherwise>
+</x:choose>
+
+<br />
+
+<hr />
+
+</body>
+</html>
diff --git a/standard/examples/web/xml/games.xml b/standard/examples/web/xml/games.xml
new file mode 100644
index 0000000..d85fc35
--- /dev/null
+++ b/standard/examples/web/xml/games.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<games>
+  <country id="Luxembourg">
+    <athlete>
+      <name>Lux 1</name>
+      <sport>swimming</sport>
+      <age>23</age>
+      <gender>M</gender>
+    </athlete>
+    <athlete>
+      <name>Lux 2</name>
+      <sport>wrestling</sport>
+      <age>31</age>
+      <gender>M</gender>
+    </athlete>
+  </country>
+  <country id="Denmark">
+    <athlete>
+      <name>Den 1</name>
+      <sport>cycling</sport>
+      <age>18</age>
+      <gender>F</gender>
+    </athlete>
+    <athlete>
+      <name>Den 2</name>
+      <sport>sailing</sport>
+      <age>27</age>
+      <gender>M</gender>
+    </athlete>
+  </country>
+</games>
\ No newline at end of file
diff --git a/standard/examples/web/xml/included.xml b/standard/examples/web/xml/included.xml
new file mode 100644
index 0000000..7bc1d9a
--- /dev/null
+++ b/standard/examples/web/xml/included.xml
@@ -0,0 +1,3 @@
+<a>
+  <b>YES!</b>
+</a>
diff --git a/standard/examples/web/xml/includedStylesheet.xsl b/standard/examples/web/xml/includedStylesheet.xsl
new file mode 100644
index 0000000..0ace8b0
--- /dev/null
+++ b/standard/examples/web/xml/includedStylesheet.xsl
@@ -0,0 +1,8 @@
+  <xsl:stylesheet
+    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
+
+  <xsl:template match="text()">
+    <h1><xsl:value-of select="."/></h1>
+  </xsl:template>
+
+  </xsl:stylesheet>
diff --git a/standard/examples/web/xml/index.html b/standard/examples/web/xml/index.html
new file mode 100644
index 0000000..304664a
--- /dev/null
+++ b/standard/examples/web/xml/index.html
@@ -0,0 +1,81 @@
+<html><!-- #BeginTemplate "/Templates/ExamplesTemplate.dwt" -->
+<head>
+<!-- #BeginEditable "doctitle" --> 
+<title>JSTL: XML Tags Examples</title>
+<!-- #EndEditable -->
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<link rel="stylesheet" href="../global.css" type="text/css">
+</head>
+
+<body bgcolor="#FFFFFF" text="#000000">
+<table width="100%" border="0" cellpadding="5">
+  <tr> 
+    <td height="0"><font color="#000099"><b>standard taglib • implementation 
+      of the JSP Standard Tag Library • </b></font><font color="#003399"><a href="mailto:taglibs-user at jakarta.apache.org"><b>support</b></a> 
+        <b><a href="mailto:taglibs-dev at jakarta.apache.org">development</a>   
+      <a href="mailto:jsr-52-comments at jcp.org">comments to JSR-52</a></b></font></td>
+  </tr>
+  <tr> 
+    <td bgcolor="#CCCCFF"><font size="-1">Examples     <a href="../index.html">Introduction</a> 
+      • <a href="../elsupport/index.html">General Purpose</a> 
+      • <a href="../conditionals/index.html">Conditionals</a> 
+      • <a href="../iterators/index.html">Iterators</a> • 
+      <a href="../import/index.jsp">Import</a> • <a href="../format/index.html">I18N 
+      & Formatting</a> • <a href="index.html">XML</a> 
+      • <a href="../sql/index.jsp">SQL</a> • <a href="../functions/index.html">Functions</a> 
+      • <a href="../tlv/index.html">TLV</a> • <a href="../functions/index.html"></a><a href="../misc/index.html">Misc.</a></font></td>
+  </tr>
+</table>
+<!-- #BeginEditable "body" --> 
+<h2>XML Examples</h2>
+<h3>Out    <a href="../ShowSource.jsp?filename=/xml/Out.jsp"> <img src="../images/code.gif" width="24" height="24" border="0"></a> 
+  <a href="Out.jsp"> <img src="../images/execute.gif" width="24" height="24" border="0"></a></h3>
+Retrieving a String from a parsed XML document <br />
+<h3>Filter    <a href="../ShowSource.jsp?filename=/xml/Filter.jsp"> 
+  <img src="../images/code.gif" width="24" height="24" border="0"></a> <a href="Filter.jsp"> 
+  <img src="../images/execute.gif" width="24" height="24" border="0"></a> </h3>
+Applying a SAX XMLFilter object to a document before parsing <br />
+<h3>ForEach    <a href="../ShowSource.jsp?filename=/xml/ForEach.jsp"> 
+  <img src="../images/code.gif" width="24" height="24" border="0"></a> <a href="ForEach.jsp"> 
+  <img src="../images/execute.gif" width="24" height="24" border="0"></a> </h3>
+Iterating over XML nodes <br />
+<h3>If    <a href="../ShowSource.jsp?filename=/xml/If.jsp"> <img src="../images/code.gif" width="24" height="24" border="0"></a> 
+  <a href="If.jsp"> <img src="../images/execute.gif" width="24" height="24" border="0"></a> 
+</h3>
+Basing a decision on the status of an XML document <br />
+<h3>Parse    <a href="../ShowSource.jsp?filename=/xml/Parse.jsp"> <img src="../images/code.gif" width="24" height="24" border="0"></a> 
+  <a href="Parse.jsp"> <img src="../images/execute.gif" width="24" height="24"
+    border="0"></a> </h3>
+Parsing XML documents directly from Objects and from URLs. <br />
+<h3>Set    <a href="../ShowSource.jsp?filename=/xml/Set.jsp"> <img src="../images/code.gif" width="24" height="24" border="0"></a> 
+  <a href="Set.jsp"> <img src="../images/execute.gif" width="24" height="24" border="0"></a> 
+</h3>
+Storing an object resulting from an XPath expression <br />
+<h3>Transform    <a href="../ShowSource.jsp?filename=/xml/Transform.jsp"> 
+  <img src="../images/code.gif" width="24" height="24" border="0"></a> <a href="Transform.jsp"> 
+  <img src="../images/execute.gif" width="24" height="24" border="0"></a> </h3>
+Applying XSLT transformations <br />
+<h3>When    <a href="../ShowSource.jsp?filename=/xml/When.jsp"> <img src="../images/code.gif" width="24" height="24" border="0"></a> 
+  <a href="When.jsp"> <img src="../images/execute.gif" width="24" height="24" border="0"></a> 
+</h3>
+Mutually exclusive conditionals based on the status of an XML document <br />
+<h3>Parse with entities    <a href="../ShowSource.jsp?filename=/xml/ParseWithEntities.jsp"> 
+  <img src="../images/code.gif" width="24" height="24" border="0"></a> <a href="ParseWithEntities.jsp"> 
+  <img src="../images/execute.gif" width="24" height="24" border="0"></a></h3>
+Parsing a document with relative entity references (using systemId) <br />
+<h3>Transform with inclusion    <a href="../ShowSource.jsp?filename=/xml/TransformWithInclusion.jsp"> 
+  <img src="../images/code.gif" width="24" height="24" border="0"></a> <a href="TransformWithInclusion.jsp"> 
+  <img src="../images/execute.gif" width="24" height="24" border="0"></a></h3>
+Transformations using XSLT tags like <xsl:include> (with xsltSystemId) <br />
+<!-- #EndEditable -->
+<hr noshade color="#000099">
+<table width="100%" border="0" cellpadding="5">
+  <tr> 
+    <td height="24"><font color="#000099"><b>standard taglib • implementation 
+      of the JSP Standard Tag Library • </b></font><font color="#003399"><a href="mailto:taglibs-user at jakarta.apache.org"><b>support</b></a> 
+        <b><a href="mailto:taglibs-dev at jakarta.apache.org">development</a>   
+      <a href="mailto:jsr-52-comments at jcp.org">comments to JSR-52</a></b></font></td>
+  </tr>
+</table>
+</body>
+<!-- #EndTemplate --></html>
diff --git a/standard/src/javax/servlet/jsp/jstl/core/ConditionalTagSupport.java b/standard/src/javax/servlet/jsp/jstl/core/ConditionalTagSupport.java
new file mode 100644
index 0000000..a36b616
--- /dev/null
+++ b/standard/src/javax/servlet/jsp/jstl/core/ConditionalTagSupport.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright 1999-2004 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 javax.servlet.jsp.jstl.core;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.JspTagException;
+import javax.servlet.jsp.PageContext;
+import javax.servlet.jsp.tagext.TagSupport;
+
+/**
+ * <p>Abstract class that facilitates implementation of conditional actions 
+ * where the boolean result is exposed as a JSP scoped variable. The 
+ * boolean result may then be used as the test condition in a <c:when>
+ * action.</p>
+ *
+ * <p>This base class provides support for:</p>
+ * 
+ * <ul>
+ *  <li> Conditional processing of the action's body based on the returned value
+ *       of the abstract method <tt>condition()</tt>.</li>
+ *  <li> Storing the result of <tt>condition()</tt> as a <tt>Boolean</tt> object
+ *       into a JSP scoped variable identified by attributes <tt>var</tt> and
+ *       <tt>scope</tt>.
+ * </ul>
+ * 
+ * @author Shawn Bayern
+ */
+
+public abstract class ConditionalTagSupport
+    extends TagSupport
+{
+    //*********************************************************************
+    // Abstract methods
+
+    /**
+     * <p>Subclasses implement this method to compute the boolean result
+     * of the conditional action. This method is invoked once per tag invocation 
+     * by <tt>doStartTag()</tt>.
+     *
+     * @return a boolean representing the condition that a particular subclass
+     *   uses to drive its conditional logic.
+     */
+    protected abstract boolean condition() throws JspTagException;
+
+
+    //*********************************************************************
+    // Constructor
+
+    /**
+     * Base constructor to initialize local state.  As with <tt>TagSupport</tt>,
+     * subclasses should not implement constructors with arguments, and
+     * no-argument constructors implemented by subclasses must call the 
+     * superclass constructor.
+     */
+    public ConditionalTagSupport() {
+        super();
+        init();
+    }
+
+
+    //*********************************************************************
+    // Lifecycle management and implementation of conditional behavior
+
+    /**
+     * Includes its body if <tt>condition()</tt> evaluates to true.
+     */
+    public int doStartTag() throws JspException {
+
+        // execute our condition() method once per invocation
+        result = condition();
+
+        // expose variables if appropriate
+        exposeVariables();
+
+        // handle conditional behavior
+        if (result)
+            return EVAL_BODY_INCLUDE;
+        else
+            return SKIP_BODY;
+    }
+
+    /**
+     * Releases any resources this ConditionalTagSupport may have (or inherit).
+     */
+    public void release() {
+        super.release();
+        init();
+    }
+
+    //*********************************************************************
+    // Private state
+
+    private boolean result;             // the saved result of condition()
+    private String var;			// scoped attribute name
+    private int scope;			// scoped attribute scope
+
+
+    //*********************************************************************
+    // Accessors
+
+    /**
+     * Sets the 'var' attribute.
+     *
+     * @param var Name of the exported scoped variable storing the result of
+     * <tt>condition()</tt>.
+     */
+    public void setVar(String var) {
+	this.var = var;
+    }
+
+    /**
+     * Sets the 'scope' attribute.
+     *
+     * @param scope Scope of the 'var' attribute
+     */
+    public void setScope(String scope) {
+	if (scope.equalsIgnoreCase("page"))
+	    this.scope = PageContext.PAGE_SCOPE;
+	else if (scope.equalsIgnoreCase("request"))
+	    this.scope = PageContext.REQUEST_SCOPE;
+	else if (scope.equalsIgnoreCase("session"))
+	    this.scope = PageContext.SESSION_SCOPE;
+	else if (scope.equalsIgnoreCase("application"))
+	    this.scope = PageContext.APPLICATION_SCOPE;
+	// TODO: Add error handling?  Needs direction from spec.
+    }
+
+
+    //*********************************************************************
+    // Utility methods
+
+    // expose attributes if we have a non-null 'var'
+    private void exposeVariables() {
+        if (var != null)
+            pageContext.setAttribute(var, new Boolean(result), scope);
+    }
+
+    // initializes internal state
+    private void init() {
+        result = false;                 // not really necessary
+	var = null;
+	scope = PageContext.PAGE_SCOPE;
+    }
+}
diff --git a/standard/src/javax/servlet/jsp/jstl/core/Config.java b/standard/src/javax/servlet/jsp/jstl/core/Config.java
new file mode 100644
index 0000000..cc7348a
--- /dev/null
+++ b/standard/src/javax/servlet/jsp/jstl/core/Config.java
@@ -0,0 +1,374 @@
+/*
+ * Copyright 1999-2004 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 javax.servlet.jsp.jstl.core;
+
+import javax.servlet.ServletContext;
+import javax.servlet.ServletRequest;
+import javax.servlet.http.HttpSession;
+import javax.servlet.jsp.PageContext;
+
+/**
+ * Class supporting access to configuration settings.
+ */
+public class Config {
+
+    /*
+     * I18N/Formatting actions related configuration data
+     */
+    
+    /**
+     * Name of configuration setting for application- (as opposed to browser-)
+     * based preferred locale
+     */
+    public static final String FMT_LOCALE
+	= "javax.servlet.jsp.jstl.fmt.locale";
+
+    /**
+     * Name of configuration setting for fallback locale
+     */
+    public static final String FMT_FALLBACK_LOCALE
+	= "javax.servlet.jsp.jstl.fmt.fallbackLocale";
+
+    /**
+     * Name of configuration setting for i18n localization context
+     */
+    public static final String FMT_LOCALIZATION_CONTEXT
+	= "javax.servlet.jsp.jstl.fmt.localizationContext";
+
+    /**
+     * Name of localization setting for time zone
+     */
+    public static final String FMT_TIME_ZONE
+	= "javax.servlet.jsp.jstl.fmt.timeZone";
+
+    /*
+     * SQL actions related configuration data
+     */
+
+    /**
+     * Name of configuration setting for SQL data source
+     */
+    public static final String SQL_DATA_SOURCE
+	= "javax.servlet.jsp.jstl.sql.dataSource";
+
+    /**
+     * Name of configuration setting for maximum number of rows to be included
+     * in SQL query result
+     */
+    public static final String SQL_MAX_ROWS
+	= "javax.servlet.jsp.jstl.sql.maxRows";
+	
+    /*
+     * Private constants
+     */
+    private static final String PAGE_SCOPE_SUFFIX = ".page";
+    private static final String REQUEST_SCOPE_SUFFIX = ".request";
+    private static final String SESSION_SCOPE_SUFFIX = ".session";
+    private static final String APPLICATION_SCOPE_SUFFIX = ".application";
+
+    /**
+     * Looks up a configuration variable in the given scope.
+     *
+     * <p> The lookup of configuration variables is performed as if each scope
+     * had its own name space, that is, the same configuration variable name
+     * in one scope does not replace one stored in a different scope.
+     *
+     * @param pc Page context in which the configuration variable is to be
+     * looked up
+     * @param name Configuration variable name
+     * @param scope Scope in which the configuration variable is to be looked
+     * up
+     *
+     * @return The <tt>java.lang.Object</tt> associated with the configuration
+     * variable, or null if it is not defined.
+     */
+    public static Object get(PageContext pc, String name, int scope) {
+	switch (scope) {
+	case PageContext.PAGE_SCOPE:
+	    return pc.getAttribute(name + PAGE_SCOPE_SUFFIX, scope);
+	case PageContext.REQUEST_SCOPE:
+	    return pc.getAttribute(name + REQUEST_SCOPE_SUFFIX, scope);
+	case PageContext.SESSION_SCOPE:
+	    return get(pc.getSession(), name);
+	case PageContext.APPLICATION_SCOPE:
+	    return pc.getAttribute(name + APPLICATION_SCOPE_SUFFIX, scope);
+	default:
+	    throw new IllegalArgumentException("unknown scope");
+	}
+    }
+
+    /**
+     * Looks up a configuration variable in the "request" scope.
+     *
+     * <p> The lookup of configuration variables is performed as if each scope
+     * had its own name space, that is, the same configuration variable name
+     * in one scope does not replace one stored in a different scope.
+     *
+     * @param request Request object in which the configuration variable is to
+     * be looked up
+     * @param name Configuration variable name
+     *
+     * @return The <tt>java.lang.Object</tt> associated with the configuration
+     * variable, or null if it is not defined.
+     */
+    public static Object get(ServletRequest request, String name) {
+	return request.getAttribute(name + REQUEST_SCOPE_SUFFIX);
+    }
+
+    /**
+     * Looks up a configuration variable in the "session" scope.
+     *
+     * <p> The lookup of configuration variables is performed as if each scope
+     * had its own name space, that is, the same configuration variable name
+     * in one scope does not replace one stored in a different scope.</p>
+     *
+     * @param session Session object in which the configuration variable is to
+     * be looked up
+     * @param name Configuration variable name
+     *
+     * @return The <tt>java.lang.Object</tt> associated with the configuration
+     * variable, or null if it is not defined, if session is null, or if the session
+     * is invalidated. 
+     */
+    public static Object get(HttpSession session, String name) {
+        Object ret = null;
+        if (session != null) {
+            try {
+                ret = session.getAttribute(name + SESSION_SCOPE_SUFFIX);
+            } catch (IllegalStateException ex) {} // when session is invalidated
+        }
+        return ret;
+    }
+
+    /**
+     * Looks up a configuration variable in the "application" scope.
+     *
+     * <p> The lookup of configuration variables is performed as if each scope
+     * had its own name space, that is, the same configuration variable name
+     * in one scope does not replace one stored in a different scope.
+     *
+     * @param context Servlet context in which the configuration variable is
+     * to be looked up
+     * @param name Configuration variable name
+     *
+     * @return The <tt>java.lang.Object</tt> associated with the configuration
+     * variable, or null if it is not defined.
+     */
+    public static Object get(ServletContext context, String name) {
+	return context.getAttribute(name + APPLICATION_SCOPE_SUFFIX);
+    }
+
+    /**
+     * Sets the value of a configuration variable in the given scope.
+     *
+     * <p> Setting the value of a configuration variable is performed as if
+     * each scope had its own namespace, that is, the same configuration
+     * variable name in one scope does not replace one stored in a different
+     * scope.
+     *
+     * @param pc Page context in which the configuration variable is to be set
+     * @param name Configuration variable name
+     * @param value Configuration variable value
+     * @param scope Scope in which the configuration variable is to be set
+     */
+    public static void set(PageContext pc, String name, Object value,
+			   int scope) {
+	switch (scope) {
+	case PageContext.PAGE_SCOPE:
+	    pc.setAttribute(name + PAGE_SCOPE_SUFFIX, value, scope);
+	    break;
+	case PageContext.REQUEST_SCOPE:
+	    pc.setAttribute(name + REQUEST_SCOPE_SUFFIX, value, scope);
+	    break;
+	case PageContext.SESSION_SCOPE:
+	    pc.setAttribute(name + SESSION_SCOPE_SUFFIX, value, scope);
+	    break;
+	case PageContext.APPLICATION_SCOPE:
+	    pc.setAttribute(name + APPLICATION_SCOPE_SUFFIX, value, scope);
+	    break;
+	default:
+	    throw new IllegalArgumentException("unknown scope");
+	}
+    }
+
+    /**
+     * Sets the value of a configuration variable in the "request" scope.
+     *
+     * <p> Setting the value of a configuration variable is performed as if
+     * each scope had its own namespace, that is, the same configuration
+     * variable name in one scope does not replace one stored in a different
+     * scope.
+     *
+     * @param request Request object in which the configuration variable is to
+     * be set
+     * @param name Configuration variable name
+     * @param value Configuration variable value
+     */
+    public static void set(ServletRequest request, String name, Object value) {
+	request.setAttribute(name + REQUEST_SCOPE_SUFFIX, value);
+    }
+
+    /**
+     * Sets the value of a configuration variable in the "session" scope.
+     *
+     * <p> Setting the value of a configuration variable is performed as if
+     * each scope had its own namespace, that is, the same configuration
+     * variable name in one scope does not replace one stored in a different
+     * scope.
+     *
+     * @param session Session object in which the configuration variable is to
+     * be set
+     * @param name Configuration variable name
+     * @param value Configuration variable value
+     */
+    public static void set(HttpSession session, String name, Object value) {
+	session.setAttribute(name + SESSION_SCOPE_SUFFIX, value);
+    }
+
+    /**
+     * Sets the value of a configuration variable in the "application" scope.
+     *
+     * <p> Setting the value of a configuration variable is performed as if
+     * each scope had its own namespace, that is, the same configuration
+     * variable name in one scope does not replace one stored in a different
+     * scope.
+     *
+     * @param context Servlet context in which the configuration variable is to
+     * be set
+     * @param name Configuration variable name
+     * @param value Configuration variable value
+     */
+    public static void set(ServletContext context, String name, Object value) {
+	context.setAttribute(name + APPLICATION_SCOPE_SUFFIX, value);
+    }
+ 
+    /**
+     * Removes a configuration variable from the given scope.
+     *
+     * <p> Removing a configuration variable is performed as if each scope had
+     * its own namespace, that is, the same configuration variable name in one
+     * scope does not impact one stored in a different scope.
+     *
+     * @param pc Page context from which the configuration variable is to be
+     * removed
+     * @param name Configuration variable name
+     * @param scope Scope from which the configuration variable is to be 
+     * removed
+     */
+    public static void remove(PageContext pc, String name, int scope) {
+	switch (scope) {
+	case PageContext.PAGE_SCOPE:
+	    pc.removeAttribute(name + PAGE_SCOPE_SUFFIX, scope);
+	    break;
+	case PageContext.REQUEST_SCOPE:
+	    pc.removeAttribute(name + REQUEST_SCOPE_SUFFIX, scope);
+	    break;
+	case PageContext.SESSION_SCOPE:
+	    pc.removeAttribute(name + SESSION_SCOPE_SUFFIX, scope);
+	    break;
+	case PageContext.APPLICATION_SCOPE:
+	    pc.removeAttribute(name + APPLICATION_SCOPE_SUFFIX, scope);
+	    break;
+	default:
+	    throw new IllegalArgumentException("unknown scope");
+	}
+    }
+
+    /**
+     * Removes a configuration variable from the "request" scope.
+     *
+     * <p> Removing a configuration variable is performed as if each scope had
+     * its own namespace, that is, the same configuration variable name in one
+     * scope does not impact one stored in a different scope.
+     * 
+     * @param request Request object from which the configuration variable is
+     * to be removed
+     * @param name Configuration variable name
+     */
+    public static void remove(ServletRequest request, String name) {
+	request.removeAttribute(name + REQUEST_SCOPE_SUFFIX);
+    }
+
+    /**
+     * Removes a configuration variable from the "session" scope.
+     *
+     * <p> Removing a configuration variable is performed as if each scope had
+     * its own namespace, that is, the same configuration variable name in one
+     * scope does not impact one stored in a different scope.
+     *
+     * @param session Session object from which the configuration variable is
+     * to be removed
+     * @param name Configuration variable name
+     */
+    public static void remove(HttpSession session, String name) {
+	session.removeAttribute(name + SESSION_SCOPE_SUFFIX);
+    }
+
+    /**
+     * Removes a configuration variable from the "application" scope.
+     *
+     * <p> Removing a configuration variable is performed as if each scope had
+     * its own namespace, that is, the same configuration variable name in one
+     * scope does not impact one stored in a different scope.
+     *
+     * @param context Servlet context from which the configuration variable is
+     * to be removed
+     * @param name Configuration variable name
+     */
+    public static void remove(ServletContext context, String name) {
+	context.removeAttribute(name + APPLICATION_SCOPE_SUFFIX);
+    }
+ 
+    /**
+     * Finds the value associated with a specific configuration setting
+     * identified by its context initialization parameter name.
+     *
+     * <p> For each of the JSP scopes (page, request, session, application),
+     * get the value of the configuration variable identified by <tt>name</tt>
+     * using method <tt>get()</tt>. Return as soon as a non-null value is
+     * found. If no value is found, get the value of the context initialization
+     * parameter identified by <tt>name</tt>.
+     *
+     * @param pc Page context in which the configuration setting is to be 
+     * searched
+     * @param name Context initialization parameter name of the configuration
+     * setting
+     * 
+     * @return The <tt>java.lang.Object</tt> associated with the configuration
+     * setting identified by <tt>name</tt>, or null if it is not defined.
+     */
+    public static Object find(PageContext pc, String name) {
+	Object ret = get(pc, name, PageContext.PAGE_SCOPE);
+	if (ret == null) {
+	    ret = get(pc, name, PageContext.REQUEST_SCOPE);
+	    if (ret == null) {
+		if (pc.getSession() != null) {
+		    // check session only if a session is present
+		    ret = get(pc, name, PageContext.SESSION_SCOPE);
+		}
+		if (ret == null) {
+		    ret = get(pc, name, PageContext.APPLICATION_SCOPE);
+		    if (ret == null) {
+			ret = pc.getServletContext().getInitParameter(name);
+		    }
+		}
+	    }
+	}
+
+	return ret;
+    }
+}
diff --git a/standard/src/javax/servlet/jsp/jstl/core/LoopTag.java b/standard/src/javax/servlet/jsp/jstl/core/LoopTag.java
new file mode 100644
index 0000000..34640db
--- /dev/null
+++ b/standard/src/javax/servlet/jsp/jstl/core/LoopTag.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 1999-2004 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 javax.servlet.jsp.jstl.core;
+
+import javax.servlet.jsp.tagext.Tag;
+
+/**
+ * <p>JSTL allows developers to write custom iteration tags by
+ * implementing the LoopTag interface.  This is not to be confused
+ * with <tt>javax.servlet.jsp.tagext.IterationTag</tt> as defined in JSP 1.2.
+ * LoopTag establishes a mechanism for iteration tags to be recognized
+ * and for type-safe implicit collaboration with custom subtags.
+ * 
+ * <p>In most cases, it will not be necessary to implement this interface
+ * manually, for a base support class (<tt>LoopTagSupport</tt>) is provided
+ * to facilitate implementation.</p>
+ *
+ * @author Shawn Bayern
+ */
+
+public interface LoopTag extends Tag {
+
+    /**
+     * Retrieves the current item in the iteration.  Behaves
+     * idempotently; calling getCurrent() repeatedly should return the same
+     * Object until the iteration is advanced.  (Specifically, calling
+     * getCurrent() does <b>not</b> advance the iteration.)
+     *
+     * @return the current item as an object
+     */
+    public Object getCurrent();
+
+    /**
+     * Retrieves a 'status' object to provide information about the
+     * current round of the iteration.
+     *
+     * @return The LoopTagStatus for the current <tt>LoopTag</tt>.
+     */
+    public LoopTagStatus getLoopStatus();
+}
diff --git a/standard/src/javax/servlet/jsp/jstl/core/LoopTagStatus.java b/standard/src/javax/servlet/jsp/jstl/core/LoopTagStatus.java
new file mode 100644
index 0000000..ebe3d46
--- /dev/null
+++ b/standard/src/javax/servlet/jsp/jstl/core/LoopTagStatus.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright 1999-2004 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 javax.servlet.jsp.jstl.core;
+
+/**
+ * <p>Exposes the current status of
+ * an iteration.  JSTL provides a mechanism for LoopTags to
+ * return information about the current index of the iteration and
+ * convenience methods to determine whether or not the current round is
+ * either the first or last in the iteration.  It also lets authors
+ * use the status object to obtain information about the iteration range,
+ * step, and current object.</p>
+ *
+ * <p>Environments that require more status can extend this interface.</p>
+ *
+ * @author Shawn Bayern
+ */
+
+public interface LoopTagStatus {
+
+    /**
+     * Retrieves the current item in the iteration.  Behaves
+     * idempotently; calling getCurrent() repeatedly should return the same
+     * Object until the iteration is advanced.  (Specifically, calling
+     * getCurrent() does <b>not</b> advance the iteration.)
+     *
+     * @return the current item as an object
+     */
+    public Object getCurrent();
+
+    /**
+     * Retrieves the index of the current round of the iteration.  If
+     * iteration is being performed over a subset of an underlying
+     * array, java.lang.Collection, or other type, the index returned
+     * is absolute with respect to the underlying collection.  Indices
+     * are 0-based.
+     *
+     * @return the 0-based index of the current round of the iteration
+     */
+    public int getIndex();
+
+    /**
+     * <p>Retrieves the "count" of the current round of the iteration.  The
+     * count is a relative, 1-based sequence number identifying the
+     * current "round" of iteration (in context with all rounds the
+     * current iteration will perform).</p>
+     *
+     * <p>As an example, an iteration with begin = 5, end = 15, and step =
+     * 5 produces the counts 1, 2, and 3 in that order.</p>
+     *
+     * @return the 1-based count of the current round of the iteration
+     */
+    public int getCount();
+
+    /**
+     * Returns information about whether the current round of the
+     * iteration is the first one.  This current round may be the 'first'
+     * even when getIndex() != 0, for 'index' refers to the absolute
+     * index of the current 'item' in the context of its underlying
+     * collection.  It is always that case that a true result from
+     * isFirst() implies getCount() == 1.
+     * 
+     * @return <tt>true</tt> if the current round is the first in the
+     * iteration, <tt>false</tt> otherwise.
+     */
+    public boolean isFirst();
+
+    /**
+     * Returns information about whether the current round of the
+     * iteration is the last one.  As with isFirst(), subsetting is
+     * taken into account.  isLast() doesn't necessarily refer to the
+     * status of the underlying Iterator; it refers to whether or not
+     * the current round will be the final round of iteration for the
+     * tag associated with this LoopTagStatus.
+     * 
+     * @return <tt>true</tt> if the current round is the last in the
+     * iteration, <tt>false</tt> otherwise.
+     */
+    public boolean isLast();
+
+    /**
+     * Returns the value of the 'begin' attribute for the associated tag,
+     * or null if no 'begin' attribute was specified.
+     *
+     * @return the 'begin' value for the associated tag, or null
+     * if no 'begin' attribute was specified
+     */
+    public Integer getBegin();
+
+    /**
+     * Returns the value of the 'end' attribute for the associated tag,
+     * or null if no 'end' attribute was specified.
+     *
+     * @return the 'end' value for the associated tag, or null
+     * if no 'end' attribute was specified
+     */
+    public Integer getEnd();
+
+    /**
+     * Returns the value of the 'step' attribute for the associated tag,
+     * or null if no 'step' attribute was specified.
+     *
+     * @return the 'step' value for the associated tag, or null
+     * if no 'step' attribute was specified
+     */
+    public Integer getStep();
+
+}
diff --git a/standard/src/javax/servlet/jsp/jstl/core/LoopTagSupport.java b/standard/src/javax/servlet/jsp/jstl/core/LoopTagSupport.java
new file mode 100644
index 0000000..56f01b5
--- /dev/null
+++ b/standard/src/javax/servlet/jsp/jstl/core/LoopTagSupport.java
@@ -0,0 +1,592 @@
+/*
+ * Copyright 1999-2004 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 javax.servlet.jsp.jstl.core;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.JspTagException;
+import javax.servlet.jsp.PageContext;
+import javax.servlet.jsp.tagext.IterationTag;
+import javax.servlet.jsp.tagext.TagSupport;
+import javax.servlet.jsp.tagext.TryCatchFinally;
+
+/**
+ * <p>Base support class to facilitate implementation of iteration tags.</p>
+ *
+ * <p>Since most iteration tags will behave identically with respect to
+ * actual iterative behavior, JSTL provides this
+ * base support class to facilitate implementation.  Many iteration tags
+ * will extend this and merely implement the <tt>hasNext()</tt> and 
+ * <tt>next()</tt> methods
+ * to provide contents for the handler to iterate over.</p>
+ *
+ * <p>In particular, this base class provides support for:</p>
+ * 
+ * <ul>
+ *  <li> Iteration control, based on protected <tt>prepare()</tt>, <tt>next()</tt>,
+ *       and <tt>hasNext()</tt> methods
+ *  <li> Subsetting (<tt>begin</tt>, <tt>end</tt>, <tt>step></tt>functionality, 
+ *       including validation
+ *       of subset parameters for sensibility)
+ *  <li> item retrieval (<tt>getCurrent()</tt>)
+ *  <li> status retrieval (<tt>LoopTagStatus</tt>)
+ *  <li> exposing attributes (set by <tt>var</tt> and <tt>varStatus</tt> attributes)
+ * </ul>
+ *
+ * <p>In providing support for these tasks, <tt>LoopTagSupport</tt> contains
+ * certain control variables that act to modify the iteration.  Accessors
+ * are provided for these control variables when the variables represent
+ * information needed or wanted at translation time (e.g., <tt>var</tt>, 
+ * <tt>varStatus</tt>).  For
+ * other variables, accessors cannot be provided here since subclasses
+ * may differ on their implementations of how those accessors are received.
+ * For instance, one subclass might accept a <tt>String</tt> and convert it into
+ * an object of a specific type by using an expression evaluator; others
+ * might accept objects directly.  Still others might not want to expose
+ * such information to outside control.</p>
+ *
+ * @author Shawn Bayern
+ */
+
+public abstract class LoopTagSupport
+    extends TagSupport
+    implements LoopTag, IterationTag, TryCatchFinally
+{
+    //*********************************************************************
+    // 'Protected' state 
+
+    /*
+     * JavaBean-style properties and other state slaved to them.  These
+     * properties can be set directly by accessors; they will not be
+     * modified by the LoopTagSupport implementation -- and should
+     * not be modified by subclasses outside accessors unless those
+     * subclasses are perfectly aware of what they're doing.
+     * (An example where such non-accessor modification might be sensible
+     * is in the doStartTag() method of an EL-aware subclass.)
+     */
+
+    /** Starting index ('begin' attribute) */
+    protected int begin;
+
+    /**
+     * Ending index of the iteration ('end' attribute).
+     * A value of -1 internally indicates 'no end
+     * specified', although accessors for the core JSTL tags do not
+     * allow this value to be supplied directly by the user.
+     */
+    protected int end;
+
+    /** Iteration step ('step' attribute) */
+    protected int step;
+
+    /** Boolean flag indicating whether 'begin' was specified. */
+    protected boolean beginSpecified;
+
+    /** Boolean flag indicating whether 'end' was specified. */
+    protected boolean endSpecified;
+
+    /** Boolean flag indicating whether 'step' was specified. */
+    protected boolean stepSpecified;
+
+    /** Attribute-exposing control */
+    protected String itemId, statusId;
+
+
+    //*********************************************************************
+    // 'Private' state (implementation details)
+
+    /*
+     * State exclusively internal to the default, reference implementation.
+     * (While this state is kept private to ensure consistency, 'status'
+     * and 'item' happen to have one-for-one, read-only, accesor methods
+     * as part of the LoopTag interface.)
+     *
+     * 'last' is kept separately for two reasons:  (a) to avoid
+     * running a computation every time it's requested, and (b) to
+     * let LoopTagStatus.isLast() avoid throwing any exceptions,
+     * which would complicate subtag and scripting-variable use.
+     *
+     * Our 'internal index' begins at 0 and increases by 'step' each
+     * round; this is arbitrary, but it seemed a simple way of keeping
+     * track of the information we need.  To avoid computing
+     * getLoopStatus().getCount() by dividing index / step, we keep
+     * a separate 'count' and increment it by 1 each round (as a minor
+     * performance improvement).
+     */
+    private LoopTagStatus status;               // our LoopTagStatus
+    private Object item;                        // the current item
+    private int index;                          // the current internal index
+    private int count;                          // the iteration count
+    private boolean last;                       // current round == last one?
+
+    //*********************************************************************
+    // Constructor
+
+    /**
+     * Constructs a new LoopTagSupport.  As with TagSupport, subclasses
+     * should not implement constructors with arguments, and no-arguments
+     * constructors implemented by subclasses must call the superclass
+     * constructor.
+     */
+    public LoopTagSupport() {
+        super();
+        init();
+    }
+
+
+    //*********************************************************************
+    // Abstract methods
+
+    /**
+     * <p>Returns the next object over which the tag should iterate.  This
+     * method must be provided by concrete subclasses of LoopTagSupport
+     * to inform the base logic about what objects it should iterate over.</p>
+     *
+     * <p>It is expected that this method will generally be backed by an
+     * Iterator, but this will not always be the case.  In particular, if
+     * retrieving the next object raises the possibility of an exception
+     * being thrown, this method allows that exception to propagate back
+     * to the JSP container as a JspTagException; a standalone Iterator
+     * would not be able to do this.  (This explains why LoopTagSupport
+     * does not simply call for an Iterator from its subtags.)</p>
+     * 
+     * @return the java.lang.Object to use in the next round of iteration
+     * @exception java.util.NoSuchElementException
+     *            if next() is called but no new elements are available
+     * @exception javax.servlet.jsp.JspTagException
+     *            for other, unexpected exceptions
+     */
+    protected abstract Object next() throws JspTagException;
+
+    /**
+     * <p>Returns information concerning the availability of more items
+     * over which to iterate.  This method must be provided by concrete
+     * subclasses of LoopTagSupport to assist the iterative logic
+     * provided by the supporting base class.</p>
+     *  
+     * <p>See <a href="#next()">next</a> for more information about the
+     * purpose and expectations behind this tag.</p>
+     *
+     * @return <tt>true</tt> if there is at least one more item to iterate
+     *         over, <tt>false</tt> otherwise
+     * @exception javax.servlet.jsp.JspTagException
+     * @see #next
+     */
+    protected abstract boolean hasNext() throws JspTagException;
+
+    /**
+     * <p>Prepares for a single tag invocation.  Specifically, allows
+     * subclasses to prepare for calls to hasNext() and next(). 
+     * Subclasses can assume that prepare() will be called once for
+     * each invocation of doStartTag() in the superclass.</p>
+     *
+     * @exception javax.servlet.jsp.JspTagException
+     */
+    protected abstract void prepare() throws JspTagException;
+
+
+    //*********************************************************************
+    // Lifecycle management and implementation of iterative behavior
+
+    /**
+     * Releases any resources this LoopTagSupport may have (or inherit).
+     */
+    public void release() {
+        super.release();
+        init();
+    }
+
+    /**
+     * Begins iterating by processing the first item.
+     */
+    public int doStartTag() throws JspException {
+        if (end != -1 && begin > end) {
+            // JSTL 1.1. We simply do not execute the loop.
+            return SKIP_BODY;
+        }
+
+        // we're beginning a new iteration, so reset our counts (etc.)
+        index = 0;
+        count = 1;
+        last = false;
+
+        // let the subclass conduct any necessary preparation
+        prepare();
+
+        // throw away the first 'begin' items (if they exist)
+        discardIgnoreSubset(begin);
+
+        // get the item we're interested in
+        if (hasNext())
+            // index is 0-based, so we don't update it for the first item
+            item = next();
+        else
+            return SKIP_BODY;
+
+        /*
+         * now discard anything we have to "step" over.
+         * (we do this in advance to support LoopTagStatus.isLast())
+         */
+        discard(step - 1);
+
+        // prepare to include our body...
+        exposeVariables();
+        calibrateLast();
+        return EVAL_BODY_INCLUDE;
+    }
+
+    /**
+     * Continues the iteration when appropriate -- that is, if we (a) have
+     * more items and (b) don't run over our 'end' (given our 'step').
+     */
+    public int doAfterBody() throws JspException {
+
+        // re-sync the index, given our prior behind-the-scenes 'step'
+        index += step - 1;
+
+        // increment the count by 1 for each round
+        count++;
+
+        // everything's been prepared for us, so just get the next item
+        if (hasNext() && !atEnd()) {
+            index++;
+            item = next();
+        } else
+            return SKIP_BODY;
+
+        /*
+         * now discard anything we have to "step" over.
+         * (we do this in advance to support LoopTagStatus.isLast())
+         */
+        discard(step - 1);
+
+        // prepare to re-iterate...
+        exposeVariables();
+        calibrateLast();
+        return EVAL_BODY_AGAIN;
+    }
+
+    /**
+     * Removes any attributes that this LoopTagSupport set.
+     *
+     * <p> These attributes are intended to support scripting variables with
+     * NESTED scope, so we don't want to pollute attribute space by leaving
+     * them lying around.
+     */
+    public void doFinally() {
+	/*
+	 * Make sure to un-expose variables, restoring them to their
+	 * prior values, if applicable.
+         */
+	unExposeVariables();
+    }
+
+    /**
+     * Rethrows the given Throwable.
+     */
+    public void doCatch(Throwable t) throws Throwable {
+	throw t;
+    }
+
+    //*********************************************************************
+    // Accessor methods
+
+    /*
+     * Overview:  The getXXX() methods we provide implement the Tag
+     * contract.  setXXX() accessors are provided only for those
+     * properties (attributes) that must be known at translation time,
+     * on the premise that these accessors will vary less than the
+     * others in terms of their interface with the page author.
+     */
+
+    /*
+     * (Purposely inherit JavaDoc and semantics from LoopTag.
+     * Subclasses can override this if necessary, but such a need is
+     * expected to be rare.)
+     */
+    public Object getCurrent() {
+        return item;
+    }
+
+    /*
+     * (Purposely inherit JavaDoc and semantics from LoopTag.
+     * Subclasses can override this method for more fine-grained control
+     * over LoopTagStatus, but an effort has been made to simplify
+     * implementation of subclasses that are happy with reasonable default
+     * behavior.)
+     */
+    public LoopTagStatus getLoopStatus() {
+
+        // local implementation with reasonable default behavior
+        class Status implements LoopTagStatus {
+
+            /*
+             * All our methods are straightforward.  We inherit
+             * our JavaDoc from LoopTagSupport; see that class
+             * for more information.
+             */
+
+            public Object getCurrent() {
+                /*
+                 * Access the item through getCurrent() instead of just
+                 * returning the item our containing class stores.  This
+                 * should allow a subclass of LoopTagSupport to override
+                 * getCurrent() without having to rewrite getLoopStatus() too.
+                 */
+                return (LoopTagSupport.this.getCurrent());
+            }
+            public int getIndex() {
+                return (index + begin);       // our 'index' isn't getIndex()
+            }
+            public int getCount() {
+                return (count);
+            }
+            public boolean isFirst() {
+                return (index == 0);          // our 'index' isn't getIndex()
+            }
+            public boolean isLast() {
+                return (last);                // use cached value
+            }
+            public Integer getBegin() {
+                if (beginSpecified)
+                    return (new Integer(begin));
+                else
+                    return null;
+            }
+            public Integer getEnd() {
+                if (endSpecified)
+                    return (new Integer(end));
+                else
+                    return null;
+            }
+            public Integer getStep() {
+                if (stepSpecified)
+                    return (new Integer(step));
+                else
+                    return null;
+            }
+        }
+
+        /*
+         * We just need one per invocation...  Actually, for the current
+         * implementation, we just need one per instance, but I'd rather
+         * not keep the reference around once release() has been called.
+         */
+        if (status == null)
+            status = new Status();
+
+        return status;
+    }
+
+    /*
+     * We only support setter methods for attributes that need to be
+     * offered as Strings or other literals; other attributes will be
+     * handled directly by implementing classes, since there might be
+     * both rtexprvalue- and EL-based varieties, which will have
+     * different signatures.  (We can't pollute child classes by having
+     * base implementations of those setters here; child classes that
+     * have attributes with different signatures would end up having
+     * two incompatible setters, which is illegal for a JavaBean.
+     */
+
+    /**
+     * Sets the 'var' attribute.
+     *
+     * @param id Name of the exported scoped variable storing the current item
+     * of the iteration.
+     */
+    public void setVar(String id) {
+        this.itemId = id;
+    }
+
+    /**
+     * Sets the 'varStatus' attribute.
+     *
+     * @param statusId Name of the exported scoped variable storing the status
+     * of the iteration.
+     */
+    public void setVarStatus(String statusId) {
+        this.statusId = statusId;
+    }
+
+
+    //*********************************************************************
+    // Protected utility methods
+
+    /* 
+     * These methods validate attributes common to iteration tags.
+     * Call them if your own subclassing implementation modifies them
+     * -- e.g., if you set them through an expression language.
+     */
+
+    /**
+     * Ensures the "begin" property is sensible, throwing an exception
+     * expected to propagate up if it isn't
+     */
+    protected void validateBegin() throws JspTagException {
+        if (begin < 0)
+            throw new JspTagException("'begin' < 0");
+    }
+
+    /**
+     * Ensures the "end" property is sensible, throwing an exception
+     * expected to propagate up if it isn't
+     */
+    protected void validateEnd() throws JspTagException {
+        if (end < 0)
+            throw new JspTagException("'end' < 0");
+    }
+
+    /**
+     * Ensures the "step" property is sensible, throwing an exception
+     * expected to propagate up if it isn't
+     */
+    protected void validateStep() throws JspTagException {
+        if (step < 1)
+            throw new JspTagException("'step' <= 0");
+    }
+
+
+    //*********************************************************************
+    // Private utility methods
+
+    /** (Re)initializes state (during release() or construction) */
+    private void init() {
+        // defaults for internal bookkeeping
+        index = 0;              // internal index always starts at 0
+        count = 1;              // internal count always starts at 1
+        status = null;          // we clear status on release()
+        item = null;            // item will be retrieved for each round
+        last = false;           // last must be set explicitly
+        beginSpecified = false; // not specified until it's specified :-)
+        endSpecified = false;   // (as above)
+        stepSpecified = false;  // (as above)
+
+        // defaults for interface with page author
+        begin = 0;              // when not specified, 'begin' is 0 by spec.
+        end = -1;               // when not specified, 'end' is not used
+        step = 1;               // when not specified, 'step' is 1
+        itemId = null;          // when not specified, no variable exported
+        statusId = null;        // when not specified, no variable exported
+    }
+
+    /** Sets 'last' appropriately. */
+    private void calibrateLast() throws JspTagException {
+        /*
+         * the current round is the last one if (a) there are no remaining
+         * elements, or (b) the next one is beyond the 'end'.
+         */
+        last = !hasNext() || atEnd() ||
+            (end != -1 && (begin + index + step > end));
+    }
+
+    /**
+     * Exposes attributes (formerly scripting variables, but no longer!)
+     * if appropriate.  Note that we don't really care, here, whether they're
+     * scripting variables or not.
+     */
+    private void exposeVariables() throws JspTagException {
+
+        /*
+         * We need to support null items returned from next(); we
+         * do this simply by passing such non-items through to the
+         * scoped variable as effectively 'null' (that is, by calling
+         * removeAttribute()).
+         *
+         * Also, just to be defensive, we handle the case of a null
+         * 'status' object as well.
+         *
+         * We call getCurrent() and getLoopStatus() (instead of just using
+         * 'item' and 'status') to bridge to subclasses correctly.
+         * A subclass can override getCurrent() or getLoopStatus() but still
+         * depend on our doStartTag() and doAfterBody(), which call this
+         * method (exposeVariables()), to expose 'item' and 'status'
+         * correctly.
+         */
+
+        if (itemId != null) {
+            if (getCurrent() == null)
+                pageContext.removeAttribute(itemId, PageContext.PAGE_SCOPE);
+            else
+                pageContext.setAttribute(itemId, getCurrent());
+        }
+        if (statusId != null) {
+            if (getLoopStatus() == null)
+                pageContext.removeAttribute(statusId, PageContext.PAGE_SCOPE);
+            else
+                pageContext.setAttribute(statusId, getLoopStatus());
+        }
+
+    }
+
+    /**
+     * Removes page attributes that we have exposed and, if applicable,
+     * restores them to their prior values (and scopes).
+     */
+    private void unExposeVariables() {
+        // "nested" variables are now simply removed
+	if (itemId != null)
+            pageContext.removeAttribute(itemId, PageContext.PAGE_SCOPE);
+	if (statusId != null)
+	    pageContext.removeAttribute(statusId, PageContext.PAGE_SCOPE);
+    }
+
+    /**
+     * Cycles through and discards up to 'n' items from the iteration.
+     * We only know "up to 'n'", not "exactly n," since we stop cycling
+     * if hasNext() returns false or if we hit the 'end' of the iteration.
+     * Note: this does not update the iteration index, since this method
+     * is intended as a behind-the-scenes operation.  The index must be
+     * updated separately.  (I don't really like this, but it's the simplest
+     * way to support isLast() without storing two separate inconsistent
+     * indices.  We need to (a) make sure hasNext() refers to the next
+     * item we actually *want* and (b) make sure the index refers to the
+     * item associated with the *current* round, not the next one.
+     * C'est la vie.)
+     */
+    private void discard(int n) throws JspTagException {
+        /*
+         * copy index so we can restore it, but we need to update it
+         * as we work so that atEnd() works
+         */
+        int oldIndex = index;
+        while (n-- > 0 && !atEnd() && hasNext()) {
+            index++;
+            next();
+        }
+        index = oldIndex;
+    }
+
+    /**
+     * Discards items ignoring subsetting rules.  Useful for discarding
+     * items from the beginning (i.e., to implement 'begin') where we
+     * don't want factor in the 'begin' value already.
+     */
+    private void discardIgnoreSubset(int n) throws JspTagException {
+	while (n-- > 0 && hasNext())
+	    next();
+    }
+
+    /**
+     * Returns true if the iteration has past the 'end' index (with
+     * respect to subsetting), false otherwise.  ('end' must be set
+     * for atEnd() to return true; if 'end' is not set, atEnd()
+     * always returns false.)
+     */
+    private boolean atEnd() {
+        return ((end != -1) && (begin + index >= end));
+    }
+}
diff --git a/standard/src/javax/servlet/jsp/jstl/fmt/LocaleSupport.java b/standard/src/javax/servlet/jsp/jstl/fmt/LocaleSupport.java
new file mode 100644
index 0000000..a57cbe2
--- /dev/null
+++ b/standard/src/javax/servlet/jsp/jstl/fmt/LocaleSupport.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright 1999-2004 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 javax.servlet.jsp.jstl.fmt;
+
+import java.text.MessageFormat;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+import javax.servlet.jsp.PageContext;
+
+import org.apache.taglibs.standard.tag.common.fmt.BundleSupport;
+import org.apache.taglibs.standard.tag.common.fmt.MessageSupport;
+
+/**
+ * Class which exposes the locale-determination logic for resource bundles
+ * through convenience methods.
+ *
+ * <p> This class may be useful to any tag handler implementation that needs
+ * to produce localized messages. For example, this might be useful for 
+ * exception messages that are intended directly for user consumption on an 
+ * error page.
+ *
+ * @author Jan Luehe
+ */
+
+public class LocaleSupport {
+
+    /** 
+     * Retrieves the localized message corresponding to the given key.
+     *
+     * <p> The given key is looked up in the resource bundle of the default
+     * I18N localization context, which is retrieved from the
+     * <tt>javax.servlet.jsp.jstl.fmt.localizationContext</tt> configuration
+     * setting.
+     *
+     * <p> If the configuration setting is empty, or the default I18N
+     * localization context does not contain any resource bundle, or the given
+     * key is undefined in its resource bundle, the string "???<key>???" is
+     * returned, where "<key>" is replaced with the given key.
+     * 
+     * @param pageContext the page in which to get the localized message
+     * corresponding to the given key  
+     * @param key the message key
+     * 
+     * @return the localized message corresponding to the given key 
+     */ 
+    public static String getLocalizedMessage(PageContext pageContext, 
+                                             String key) {
+	return getLocalizedMessage(pageContext, key, null, null);
+    }
+
+    /** 
+     * Retrieves the localized message corresponding to the given key.
+     *
+     * <p> The given key is looked up in the resource bundle with the given
+     * base name.
+     *
+     * <p> If no resource bundle with the given base name exists, or the given
+     * key is undefined in the resource bundle, the string "???<key>???" is
+     * returned, where "<key>" is replaced with the given key.
+     * 
+     * @param pageContext the page in which to get the localized message
+     * corresponding to the given key  
+     * @param key the message key
+     * @param basename the resource bundle base name 
+     * 
+     * @return the localized message corresponding to the given key 
+     */ 
+    public static String getLocalizedMessage(PageContext pageContext, 
+                                             String key, 
+                                             String basename) {
+	return getLocalizedMessage(pageContext, key, null, basename);
+    }
+
+    /**
+     * Retrieves the localized message corresponding to the given key, and
+     * performs parametric replacement using the arguments specified via
+     * <tt>args</tt>.
+     *
+     * <p> See the specification of the <fmt:message> action for a description
+     * of how parametric replacement is implemented.
+     *
+     * <p> The localized message is retrieved as in
+     * {@link #getLocalizedMessage(javax.servlet.jsp.PageContext,java.lang.String) getLocalizedMessage(pageContext, key)}.
+     *
+     * @param pageContext the page in which to get the localized message
+     * corresponding to the given key  
+     * @param key the message key
+     * @param args the arguments for parametric replacement 
+     * 
+     * @return the localized message corresponding to the given key 
+     */ 
+    public static String getLocalizedMessage(PageContext pageContext, 
+                                             String key, 
+                                             Object[] args) {
+	return getLocalizedMessage(pageContext, key, args, null);
+    }
+
+    /**
+     * Retrieves the localized message corresponding to the given key, and
+     * performs parametric replacement using the arguments specified via
+     * <tt>args</tt>.
+     *
+     * <p> See the specification of the <fmt:message> action for a description
+     * of how parametric replacement is implemented.
+     *
+     * <p> The localized message is retrieved as in
+     * {@link #getLocalizedMessage(javax.servlet.jsp.PageContext,java.lang.String, java.lang.String) getLocalizedMessage(pageContext, key, basename)}.
+     * 
+     * @param pageContext the page in which to get the localized message
+     * corresponding to the given key  
+     * @param key the message key
+     * @param args the arguments for parametric replacement 
+     * @param basename the resource bundle base name 
+     * 
+     * @return the localized message corresponding to the given key 
+     */ 
+    public static String getLocalizedMessage(PageContext pageContext, 
+                                             String key, 
+                                             Object[] args, 
+                                             String basename) {
+	LocalizationContext locCtxt = null;
+	String message = MessageSupport.UNDEFINED_KEY + key
+	    + MessageSupport.UNDEFINED_KEY;
+
+	if (basename != null) {
+	    locCtxt = BundleSupport.getLocalizationContext(pageContext, basename);
+	} else {
+	    locCtxt = BundleSupport.getLocalizationContext(pageContext);
+	}
+
+	if (locCtxt != null) {
+	    ResourceBundle bundle = locCtxt.getResourceBundle();
+	    if (bundle != null) {
+		try {
+		    message = bundle.getString(key);
+		    if (args != null) {
+			MessageFormat formatter = new MessageFormat("");
+			if (locCtxt.getLocale() != null) {
+			    formatter.setLocale(locCtxt.getLocale());
+			}
+			formatter.applyPattern(message);
+			message = formatter.format(args);
+		    }
+		} catch (MissingResourceException mre) {
+		}
+	    }
+	}
+
+	return message;
+    }
+}
+
diff --git a/standard/src/javax/servlet/jsp/jstl/fmt/LocalizationContext.java b/standard/src/javax/servlet/jsp/jstl/fmt/LocalizationContext.java
new file mode 100644
index 0000000..8b8f6d1
--- /dev/null
+++ b/standard/src/javax/servlet/jsp/jstl/fmt/LocalizationContext.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright 1999-2004 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 javax.servlet.jsp.jstl.fmt;
+
+import java.util.Locale;
+import java.util.ResourceBundle;
+
+/**
+ * Class representing an I18N localization context.
+ *
+ * <p> An I18N localization context has two components: a resource bundle and
+ * the locale that led to the resource bundle match.
+ *
+ * <p> The resource bundle component is used by <fmt:message> for mapping
+ * message keys to localized messages, and the locale component is used by the
+ * <fmt:message>, <fmt:formatNumber>, <fmt:parseNumber>, <fmt:formatDate>,
+ * and <fmt:parseDate> actions as their formatting or parsing locale, respectively.
+ *
+ * @author Jan Luehe
+ */
+
+public class LocalizationContext {
+
+    // the localization context's resource bundle
+    final private ResourceBundle bundle;
+
+    // the localization context's locale
+    final private Locale locale;
+
+    /**
+     * Constructs an empty I18N localization context.
+     */
+    public LocalizationContext() {
+	bundle = null;
+	locale = null;
+    }
+
+    /**
+     * Constructs an I18N localization context from the given resource bundle
+     * and locale.
+     *
+     * <p> The specified locale is the application- or browser-based preferred
+     * locale that led to the resource bundle match.
+     *
+     * @param bundle The localization context's resource bundle
+     * @param locale The localization context's locale
+     */
+    public LocalizationContext(ResourceBundle bundle, Locale locale) {
+	this.bundle = bundle;
+	this.locale = locale;
+    }
+
+    /**
+     * Constructs an I18N localization context from the given resource bundle.
+     *
+     * <p> The localization context's locale is taken from the given
+     * resource bundle.
+     *
+     * @param bundle The resource bundle
+     */
+    public LocalizationContext(ResourceBundle bundle) {
+	this.bundle = bundle;
+	this.locale = bundle.getLocale();
+    }
+
+    /** 
+     * Gets the resource bundle of this I18N localization context.
+     * 
+     * @return The resource bundle of this I18N localization context, or null
+     * if this I18N localization context is empty
+     */ 
+    public ResourceBundle getResourceBundle() {
+	return bundle;
+    }
+
+    /** 
+     * Gets the locale of this I18N localization context.
+     *
+     * @return The locale of this I18N localization context, or null if this
+     * I18N localization context is empty, or its resource bundle is a
+     * (locale-less) root resource bundle.
+     */ 
+    public Locale getLocale() {
+	return locale;
+    }
+}
+
diff --git a/standard/src/javax/servlet/jsp/jstl/sql/Result.java b/standard/src/javax/servlet/jsp/jstl/sql/Result.java
new file mode 100644
index 0000000..e98d431
--- /dev/null
+++ b/standard/src/javax/servlet/jsp/jstl/sql/Result.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright 1999-2004 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 javax.servlet.jsp.jstl.sql;
+
+import java.util.SortedMap;
+
+/**
+ * <p>This interface represents the result of a <sql:query>
+ * action. It provides access to the following information in the
+ * query result:</p>
+ *
+ * <ul>
+ * <li> The result rows (<tt>getRows()</tt> and <tt>getRowsByIndex()</tt>)
+ * <li> The column names (<tt>getColumnNames()</tt>)
+ * <li> The number of rows in the result (<tt>getRowCount()</tt>)
+ * <li> An indication whether the rows returned represent the complete result 
+ *      or just a subset that is limited by a maximum row setting
+ *      (<tt>isLimitedByMaxRows()</tt>)
+ * </ul>
+ *
+ * <p>An implementation of the <tt>Result</tt> interface provides a
+ * <i>disconnected</i> view into the result of a query.
+ *
+ * @author Justyna Horwat
+ *
+ */
+public interface Result {
+
+    /**
+     * <p>Returns the result of the query as an array of <code>SortedMap</code> objects. 
+     * Each item of the array represents a specific row in the query result.</p>
+     *
+     * <p>A row is structured as a <code>SortedMap</code> object where the key is the column name, 
+     * and where the value is the value associated with the column identified by 
+     * the key. The column value is an Object of the Java type corresponding 
+     * to the mapping between column types and Java types defined by the JDBC 
+     * specification when the <code>ResultSet.getObject()</code> method is used.</p>
+     *
+     * <p>The <code>SortedMap</code> must use the <code>Comparator</code> 
+     * <code>java.util.String.CASE_INSENSITIVE_ORDER</code>. 
+     * This makes it possible to access the key as a case insensitive representation 
+     * of a column name. This method will therefore work regardless of the case of 
+     * the column name returned by the database.</p>
+     *
+     * @return The result rows as an array of <code>SortedMap</code> objects
+     */
+    public SortedMap[] getRows();
+
+    /**
+     * Returns the result of the query as an array of arrays. 
+     * The first array dimension represents a specific row in the query result. 
+     * The array elements for each row are Object instances of the Java type 
+     * corresponding to the mapping between column types and Java types defined 
+     * by the JDBC specification when the <code>ResultSet.getObject()</code> method is used.
+     *
+     * @return the result rows as an array of <code>Object[]</code> objects
+     */
+    public Object[][] getRowsByIndex();
+
+    /**
+     * Returns the names of the columns in the result. The order of the names in the array 
+     * matches the order in which columns are returned in method getRowsByIndex().
+     *
+     * @return the column names as an array of <code>String</code> objects
+     */
+    public String[] getColumnNames();
+
+    /**
+     * Returns the number of rows in the cached ResultSet
+     *
+     * @return the number of rows in the result
+     */
+    public int getRowCount();
+
+    /**
+     * Returns true if the query was limited by a maximum row setting
+     *
+     * @return <tt>true</tt> if the query was limited by a maximum
+     * row setting
+     */
+    public boolean isLimitedByMaxRows();
+}
diff --git a/standard/src/javax/servlet/jsp/jstl/sql/ResultImpl.java b/standard/src/javax/servlet/jsp/jstl/sql/ResultImpl.java
new file mode 100644
index 0000000..ff48a15
--- /dev/null
+++ b/standard/src/javax/servlet/jsp/jstl/sql/ResultImpl.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright 1999-2004 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 javax.servlet.jsp.jstl.sql;
+
+import java.io.Serializable;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+/**
+ * <p>This class creates a cached version of a <tt>ResultSet</tt>.
+ * It's represented as a <tt>Result</tt> implementation, capable of 
+ * returing an array of <tt>Row</tt> objects containing a <tt>Column</tt> 
+ * instance for each column in the row.   It is not part of the JSTL
+ * API; it serves merely as a back-end to ResultSupport's static methods.
+ * Thus, we scope its access to the package.
+ *
+ * @author Hans Bergsten
+ * @author Justyna Horwat
+ */
+
+class ResultImpl implements Result, Serializable {
+    private List rowMap;
+    private List rowByIndex;
+    private String[] columnNames;
+    private boolean isLimited;
+
+    /**
+     * This constructor reads the ResultSet and saves a cached
+     * copy.
+     * It's important to note that this object will be serializable only
+     * if the objects returned by the ResultSet are serializable too.
+     *
+     * @param rs an open <tt>ResultSet</tt>, positioned before the first
+     * row
+     * @param startRow beginning row to be cached
+     * @param maxRows query maximum rows limit
+     * @exception java.sql.SQLException if a database error occurs
+     */
+    public ResultImpl(ResultSet rs, int startRow, int maxRows)
+        throws SQLException 
+    {
+        rowMap = new ArrayList();
+        rowByIndex = new ArrayList();
+
+        ResultSetMetaData rsmd = rs.getMetaData();
+        int noOfColumns = rsmd.getColumnCount();
+
+        // Create the column name array
+        columnNames = new String[noOfColumns];
+        for (int i = 1; i <= noOfColumns; i++) {
+            columnNames[i-1] = rsmd.getColumnName(i);
+        }
+
+        // Throw away all rows upto startRow
+        for (int i = 0; i < startRow; i++) {
+            rs.next();
+        }
+
+        // Process the remaining rows upto maxRows
+        int processedRows = 0;
+        while (rs.next()) {
+            if ((maxRows != -1) && (processedRows == maxRows)) {
+                isLimited = true; 
+                break;
+            }
+            Object[] columns = new Object[noOfColumns];
+            SortedMap columnMap = 
+                new TreeMap(String.CASE_INSENSITIVE_ORDER);
+
+            // JDBC uses 1 as the lowest index!
+            for (int i = 1; i <= noOfColumns; i++) {
+                Object value =  rs.getObject(i);
+                if (rs.wasNull()) {
+                    value = null;
+                }
+                columns[i-1] = value;
+                columnMap.put(columnNames[i-1], value);
+            }
+            rowMap.add(columnMap);
+            rowByIndex.add(columns);
+            processedRows++;
+        }
+    }
+
+    /**
+     * Returns an array of SortedMap objects. The SortedMap
+     * object key is the ColumnName and the value is the ColumnValue.
+     * SortedMap was created using the CASE_INSENSITIVE_ORDER
+     * Comparator so the key is the case insensitive representation
+     * of the ColumnName.
+     *
+     * @return an array of Map, or null if there are no rows
+     */
+    public SortedMap[] getRows() {
+        if (rowMap == null) {
+            return null;
+        }
+
+        //should just be able to return SortedMap[] object
+        return (SortedMap []) rowMap.toArray(new SortedMap[0]);
+    }
+
+
+    /**
+     * Returns an array of Object[] objects. The first index
+     * designates the Row, the second the Column. The array
+     * stores the value at the specified row and column.
+     *
+     * @return an array of Object[], or null if there are no rows
+     */
+    public Object[][] getRowsByIndex() {
+        if (rowByIndex == null) {
+            return null;
+        }
+
+        //should just be able to return Object[][] object
+        return (Object [][])rowByIndex.toArray(new Object[0][0]);
+    }
+
+    /**
+     * Returns an array of String objects. The array represents
+     * the names of the columns arranged in the same order as in
+     * the getRowsByIndex() method.
+     *
+     * @return an array of String[]
+     */
+    public String[] getColumnNames() {
+        return columnNames;
+    }
+
+    /**
+     * Returns the number of rows in the cached ResultSet
+     *
+     * @return the number of cached rows, or -1 if the Result could
+     *    not be initialized due to SQLExceptions
+     */
+    public int getRowCount() {
+        if (rowMap == null) {
+            return -1;
+        }
+        return rowMap.size();
+    }
+
+    /**
+     * Returns true if the query was limited by a maximum row setting
+     *
+     * @return true if the query was limited by a MaxRows attribute
+     */
+    public boolean isLimitedByMaxRows() {
+        return isLimited;
+    }
+
+}
diff --git a/standard/src/javax/servlet/jsp/jstl/sql/ResultSupport.java b/standard/src/javax/servlet/jsp/jstl/sql/ResultSupport.java
new file mode 100644
index 0000000..bfab963
--- /dev/null
+++ b/standard/src/javax/servlet/jsp/jstl/sql/ResultSupport.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright 1999-2004 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 javax.servlet.jsp.jstl.sql;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+/**
+ * <p>Supports the creation of a javax.servlet.jsp.jstl.sql.Result object 
+ * from a source java.sql.ResultSet object. A Result object makes it much 
+ * easier for page authors to access and manipulate the data resulting 
+ * from a SQL query.</p>
+ *
+ * @author Justyna Horwat
+ *
+ */
+public class ResultSupport {
+
+
+    /**
+     * Converts a <code>ResultSet</code> object to a <code>Result</code> object.
+     *
+     * @param rs the <code>ResultSet</code> object
+     *
+     * @return The <code>Result</code> object created from the <code>ResultSet</code>
+     */
+    public static Result toResult(ResultSet rs) {
+        try {
+            return new ResultImpl(rs, -1, -1);
+        } catch (SQLException ex) {
+            return null;
+        }
+    }
+
+    /**
+     * Converts <code>maxRows</code> of a <code>ResultSet</code> object to a 
+     * <code>Result</code> object.
+     *
+     * @param rs the <code>ResultSet</code> object
+     * @param maxRows the maximum number of rows to be cached into the <code>Result</code> object.
+     *
+     * @return The <code>Result</code> object created from the <code>ResultSet</code>,
+     * limited by <code>maxRows</code>
+     */
+    public static Result toResult(ResultSet rs, int maxRows) {
+        try {
+            return new ResultImpl(rs, -1, maxRows);
+        } catch (SQLException ex) {
+            return null;
+        }
+    }
+
+}
diff --git a/standard/src/javax/servlet/jsp/jstl/sql/SQLExecutionTag.java b/standard/src/javax/servlet/jsp/jstl/sql/SQLExecutionTag.java
new file mode 100644
index 0000000..4a00acd
--- /dev/null
+++ b/standard/src/javax/servlet/jsp/jstl/sql/SQLExecutionTag.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 1999-2004 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 javax.servlet.jsp.jstl.sql;
+
+/**
+ * <p>This interface allows tag handlers implementing it to receive
+ * values for parameter markers in their SQL statements.</p>
+ *
+ * <p>This interface is implemented by both <sql:query> and
+ * <sql:update>. Its <code>addSQLParameter()</code> method
+ * is called by nested parameter actions (such as <sql:param>)
+ * to substitute <code>PreparedStatement</code> parameter values for
+ * "?" parameter markers in the SQL statement of the enclosing
+ * <code>SQLExecutionTag</code> action.</p>
+ *
+ * <p>The given parameter values are converted to their corresponding
+ * SQL type (following the rules in the JDBC specification) before
+ * they are sent to the database.</p>
+ *
+ * <p>Keeping track of the index of the parameter values being added
+ * is the responsibility of the tag handler implementing this
+ * interface</p>
+ *
+ * <p>The <code>SQLExcecutionTag</code> interface is exposed in order
+ * to support custom parameter actions which may retrieve their
+ * parameters from any source and process them before substituting
+ * them for a parameter marker in the SQL statement of the
+ * enclosing <code>SQLExecutionTag</code> action</p>
+ *
+ * @author Justyna Horwat
+ */
+public interface SQLExecutionTag {
+
+    /**
+     * Adds a PreparedStatement parameter value. 
+     * Must behave as if it calls <code>PreparedStatement.setObject(int, Object)</code>. 
+     * For each tag invocation, the integral index passed logically to <code>setObject()</code> 
+     * must begin with 1 and must be incremented by 1 for each subsequent invocation 
+     * of <code>addSQLParameter()</code>. The Object logically passed to <code>setObject()</code> must be the 
+     * unmodified object received in the value argument.
+     *
+     * @param value the <code>PreparedStatement</code> parameter value
+     */
+    public void addSQLParameter(Object value);
+}
diff --git a/standard/src/javax/servlet/jsp/jstl/tlv/PermittedTaglibsTLV.java b/standard/src/javax/servlet/jsp/jstl/tlv/PermittedTaglibsTLV.java
new file mode 100644
index 0000000..4ba23d1
--- /dev/null
+++ b/standard/src/javax/servlet/jsp/jstl/tlv/PermittedTaglibsTLV.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright 1999-2004 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 javax.servlet.jsp.jstl.tlv;
+
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.StringTokenizer;
+
+import javax.servlet.jsp.tagext.PageData;
+import javax.servlet.jsp.tagext.TagLibraryValidator;
+import javax.servlet.jsp.tagext.ValidationMessage;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+/**
+ * <p>A TagLibraryValidator class to allow a TLD to restrict what
+ * taglibs (in addition to itself) may be imported on a page where it's
+ * used.</p>
+ *
+ * <p>This TLV supports the following initialization parameter:</p>
+ * <ul>
+ * <li><b>permittedTaglibs</b>: A whitespace-separated list of URIs corresponding 
+ *   to tag libraries permitted to be imported on the page in addition to the tag 
+ *   library that references PermittedTaglibsTLV (which is allowed implicitly).
+ * </ul>
+ *
+ * @author Shawn Bayern
+ */
+public class PermittedTaglibsTLV extends TagLibraryValidator {
+
+    //*********************************************************************
+    // Constants
+
+    // parameter names
+    private final String PERMITTED_TAGLIBS_PARAM = "permittedTaglibs";
+
+    // URI for "<jsp:root>" element
+    private final String JSP_ROOT_URI = "http://java.sun.com/JSP/Page";
+
+    // local name of "<jsp:root>" element
+    private final String JSP_ROOT_NAME = "root";
+
+    // QName for "<jsp:root>" element
+    private final String JSP_ROOT_QN = "jsp:root";
+
+
+    //*********************************************************************
+    // Validation and configuration state (protected)
+
+    private Set permittedTaglibs;		// what URIs are allowed?
+    private boolean failed;			// did the page fail?
+    private String uri;				// our taglib's URI
+
+    //*********************************************************************
+    // Constructor and lifecycle management
+
+    public PermittedTaglibsTLV() {
+	super();
+	init();
+    }
+
+    private void init() {
+	permittedTaglibs = null;
+    }
+
+    public void release() {
+	super.release();
+	init();
+    }
+    
+
+    //*********************************************************************
+    // Validation entry point
+
+    public synchronized ValidationMessage[] validate(
+	    String prefix, String uri, PageData page) {
+	try {
+
+	    // initialize
+	    this.uri = uri;
+	    permittedTaglibs = readConfiguration();
+
+	    // get a handler
+	    DefaultHandler h = new PermittedTaglibsHandler();
+
+	    // parse the page
+	    SAXParserFactory f = SAXParserFactory.newInstance();
+	    f.setValidating(true);
+	    SAXParser p = f.newSAXParser();
+	    p.parse(page.getInputStream(), h);
+
+	    if (failed)
+		return vmFromString(
+		    "taglib " + prefix + " (" + uri + ") allows only the "
+		    + "following taglibs to be imported: " + permittedTaglibs);
+	    else
+		return null;
+
+	} catch (SAXException ex) {
+	    return vmFromString(ex.toString());
+	} catch (ParserConfigurationException ex) {
+	    return vmFromString(ex.toString());
+	} catch (IOException ex) {
+	    return vmFromString(ex.toString());
+	}
+    }
+
+
+    //*********************************************************************
+    // Utility functions
+
+    /** Returns Set of permitted taglibs, based on configuration data. */
+    private Set readConfiguration() {
+
+	// initialize the Set
+	Set s = new HashSet();
+
+	// get the space-separated list of taglibs
+	String uris = (String) getInitParameters().get(PERMITTED_TAGLIBS_PARAM);
+
+        // separate the list into individual uris and store them
+        StringTokenizer st = new StringTokenizer(uris);
+        while (st.hasMoreTokens())
+	    s.add(st.nextToken());
+
+	// return the new Set
+	return s;
+
+    }
+
+    // constructs a ValidationMessage[] from a single String and no ID
+    private ValidationMessage[] vmFromString(String message) {
+	return new ValidationMessage[] {
+	    new ValidationMessage(null, message)
+	};
+    }
+
+
+    //*********************************************************************
+    // SAX handler
+
+    /** The handler that provides the base of our implementation. */
+    private class PermittedTaglibsHandler extends DefaultHandler {
+
+        // if the element is <jsp:root>, check its "xmlns:" attributes
+        public void startElement(
+                String ns, String ln, String qn, Attributes a) {
+
+	    // ignore all but <jsp:root>
+	    if (!qn.equals(JSP_ROOT_QN) &&
+	            (!ns.equals(JSP_ROOT_URI) || !ln.equals(JSP_ROOT_NAME)))
+		return;
+
+	    // for <jsp:root>, check the attributes
+	    for (int i = 0; i < a.getLength(); i++) {
+		String name = a.getQName(i);
+
+		// ignore non-namespace attributes, and xmlns:jsp
+		if (!name.startsWith("xmlns:") || name.equals("xmlns:jsp"))
+		    continue;
+
+		String value = a.getValue(i);
+		// ignore our own namespace declaration
+		if (value.equals(uri))
+		    continue;
+
+		// otherwise, ensure that 'value' is in 'permittedTaglibs' set
+		if (!permittedTaglibs.contains(value))
+		    failed = true;
+	    }
+	}
+    }
+
+}
diff --git a/standard/src/javax/servlet/jsp/jstl/tlv/ScriptFreeTLV.java b/standard/src/javax/servlet/jsp/jstl/tlv/ScriptFreeTLV.java
new file mode 100644
index 0000000..d82b5c1
--- /dev/null
+++ b/standard/src/javax/servlet/jsp/jstl/tlv/ScriptFreeTLV.java
@@ -0,0 +1,245 @@
+/*
+ * Copyright 1999-2004 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 javax.servlet.jsp.jstl.tlv;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Map;
+
+import javax.servlet.jsp.tagext.PageData;
+import javax.servlet.jsp.tagext.TagLibraryValidator;
+import javax.servlet.jsp.tagext.ValidationMessage;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+/**
+ * <p>A TagLibraryValidator for enforcing restrictions against
+ * the use of JSP scripting elements.</p>
+ * <p>This TLV supports four initialization parameters, for controlling
+ * which of the four types of scripting elements are allowed or prohibited:</p>
+ * <ul>
+ * <li><b>allowDeclarations</b>: if true, indicates that declaration elements
+ * are not prohibited.
+ * <li><b>allowScriptlets</b>: if true, indicates that scriptlets are not
+ * prohibited
+ * <li><b>allowExpressions</b>: if true, indicates that top-level expression
+ * elements (i.e., expressions not associated with request-time attribute
+ * values) are not prohibited.
+ * <li><b>allowRTExpressions</b>: if true, indicates that expression elements
+ * associated with request-time attribute values are not prohibited.
+ * </ul>
+ * <p>The default value for all for initialization parameters is false,
+ * indicating all forms of scripting elements are to be prohibited.</p>
+ * 
+ * @author <a href="mailto:mak at taglib.com">Mark A. Kolb</a>
+ * @author Shawn Bayern (minor changes)
+ */
+public class ScriptFreeTLV extends TagLibraryValidator {
+  private boolean allowDeclarations = false;
+  private boolean allowScriptlets = false;
+  private boolean allowExpressions = false;
+  private boolean allowRTExpressions = false;
+  private SAXParserFactory factory;
+
+  /**
+   * Constructs a new validator instance.
+   * Initializes the parser factory to create non-validating, namespace-aware
+   * SAX parsers.
+   */
+  public ScriptFreeTLV () {
+    factory = SAXParserFactory.newInstance();
+    factory.setValidating(false);
+    factory.setNamespaceAware(true);
+  }
+
+  /**
+   * Sets the values of the initialization parameters, as supplied in the TLD.
+   * @param initParms a mapping from the names of the initialization parameters
+   * to their values, as specified in the TLD.
+   */
+  public void setInitParameters (Map initParms) {
+    super.setInitParameters(initParms);
+    String declarationsParm = (String) initParms.get("allowDeclarations");
+    String scriptletsParm = (String) initParms.get("allowScriptlets");
+    String expressionsParm = (String) initParms.get("allowExpressions");
+    String rtExpressionsParm = (String) initParms.get("allowRTExpressions");
+
+    allowDeclarations = "true".equalsIgnoreCase(declarationsParm);
+    allowScriptlets = "true".equalsIgnoreCase(scriptletsParm);
+    allowExpressions = "true".equalsIgnoreCase(expressionsParm);
+    allowRTExpressions = "true".equalsIgnoreCase(rtExpressionsParm);
+  }
+
+  /**
+   * Validates a single JSP page.
+   * @param prefix the namespace prefix specified by the page for the
+   * custom tag library being validated.
+   * @param uri the URI specified by the page for the TLD of the
+   * custom tag library being validated.
+   * @param page a wrapper around the XML representation of the page
+   * being validated.
+   * @return null, if the page is valid; otherwise, a ValidationMessage[]
+   * containing one or more messages indicating why the page is not valid.
+   */
+  public ValidationMessage[] validate
+      (String prefix, String uri, PageData page) {
+    InputStream in = null;
+    SAXParser parser;
+    MyContentHandler handler = new MyContentHandler();
+    try {
+      synchronized (factory) {
+	parser = factory.newSAXParser();
+      }
+      in = page.getInputStream();
+      parser.parse(in, handler);
+    }
+    catch (ParserConfigurationException e) {
+      return vmFromString(e.toString());
+    }
+    catch (SAXException e) {
+      return vmFromString(e.toString());
+    }
+    catch (IOException e) {
+      return vmFromString(e.toString());
+    }
+    finally {
+      if (in != null) try { in.close(); } catch (IOException e) {}
+    }
+    return handler.reportResults();
+  }
+
+  /** 
+   * Handler for SAX events. 
+   * Four counters are provided as instance variables,
+   * for counting occurrences of prohibited scripting elements.
+   */
+  private class MyContentHandler extends DefaultHandler {
+    private int declarationCount = 0;
+    private int scriptletCount = 0;
+    private int expressionCount = 0;
+    private int rtExpressionCount = 0;
+
+    /** 
+     * This event is received whenever a new element is encountered.
+     * The qualified name of each such element is compared against
+     * the names of any prohibited scripting elements. When found, the
+     * corresponding counter is incremented.
+     * If expressions representing request-time attribute values are
+     * prohibited, it is also necessary to check the values of all
+     * attributes specified by the element. (Trying to figure out
+     * which attributes actually support request-time attribute values
+     * and checking only those is far more trouble than it's worth.)
+     */
+    public void startElement (String namespaceUri, 
+			      String localName, String qualifiedName,
+			      Attributes atts) {
+      if ((! allowDeclarations)
+	  && qualifiedName.equals("jsp:declaration"))
+	++declarationCount;
+      else if ((! allowScriptlets)
+	       && qualifiedName.equals("jsp:scriptlet"))
+	++scriptletCount;
+      else if ((! allowExpressions)
+	       && qualifiedName.equals("jsp:expression"))
+	++expressionCount;
+      if (! allowRTExpressions) countRTExpressions(atts);
+    }
+
+    /**
+     * Auxiliary method for checking attribute values to see if
+     * are specified via request-time attribute values.
+     * Expressions representing request-time attribute values are
+     * recognized by their "%=" and "%" delimiters. When found, the
+     * corresponding counter is incremented.
+     */
+    private void countRTExpressions (Attributes atts) {
+      int stop = atts.getLength();
+      for (int i = 0; i < stop; ++i) {
+	String attval = atts.getValue(i);
+	if (attval.startsWith("%=") && attval.endsWith("%"))
+	  ++rtExpressionCount;
+      }
+    }
+
+    /**
+     * Constructs a String reporting the number(s) of prohibited
+     * scripting elements that were detected, if any.
+     * Returns null if no violations were found, making the result
+     * of this method suitable for the return value of the
+     * TagLibraryValidator.validate() method.
+     * 
+     * TODO:  The update from 7/13/2001 merely makes this validator
+     * compliant with the new TLV API, but does not fully take advantage
+     * of this API.  In the future, we should do so... but because
+     * of the possibility that anti-script checking will be incorporated
+     * into the base TLV, I've held off for now and just changed this
+     * class to use the new API.  -- SB.
+     */
+    public ValidationMessage[] reportResults () {
+      if (declarationCount + scriptletCount + expressionCount 
+          + rtExpressionCount > 0) {
+	StringBuffer results = new StringBuffer("JSP page contains ");
+	boolean first = true;
+	if (declarationCount > 0) {
+	  results.append(Integer.toString(declarationCount));
+	  results.append(" declaration");
+	  if (declarationCount > 1) results.append('s');
+	  first = false;
+	}
+	if (scriptletCount > 0) {
+	  if (! first) results.append(", ");
+	  results.append(Integer.toString(scriptletCount));
+	  results.append(" scriptlet");
+	  if (scriptletCount > 1) results.append('s');
+	  first = false;
+	}
+	if (expressionCount > 0) {
+	  if (! first) results.append(", ");
+	  results.append(Integer.toString(expressionCount));
+	  results.append(" expression");
+	  if (expressionCount > 1) results.append('s');
+	  first = false;
+	}
+	if (rtExpressionCount > 0) {
+	  if (! first) results.append(", ");
+	  results.append(Integer.toString(rtExpressionCount));
+	  results.append(" request-time attribute value");
+	  if (rtExpressionCount > 1) results.append('s');
+	  first = false;
+	}
+	results.append(".");
+	return vmFromString(results.toString());
+      } else {
+	return null;
+      }
+    }
+  }
+
+
+  // constructs a ValidationMessage[] from a single String and no ID
+  private static ValidationMessage[] vmFromString(String message) {
+    return new ValidationMessage[] {
+      new ValidationMessage(null, message)
+    };
+  }
+
+}
diff --git a/standard/src/org/apache/taglibs/standard/Version.java b/standard/src/org/apache/taglibs/standard/Version.java
new file mode 100644
index 0000000..bc66d9b
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/Version.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright 1999,2004 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.taglibs.standard;
+
+/**
+ * [lifted from xalan]
+ * <meta name="usage" content="general"/>
+ * Administrative class to keep track of the version number of
+ * the standard tag library.
+ * <P>This class implements the upcoming standard of having
+ * org.apache.project-name.Version.getVersion() be a standard way 
+ * to get version information.  
+ */
+public class Version
+{
+  /**
+   * Get the basic version string for the current release.
+   * Version String formatted like 
+   * <CODE>"<B>standard-taglib</B> v.r[.dd| <B>D</B>nn]"</CODE>.
+   *
+   * Futurework: have this read version info from jar manifest.
+   *
+   * @return String denoting our current version
+   */
+  public static String getVersion()
+  {
+    return getProduct() + " " +
+           getMajorVersionNum() + "." + getReleaseVersionNum()+ "." +
+           getMaintenanceVersionNum() +
+           ((getDevelopmentVersionNum() > 0) ? 
+               ("_D" + getDevelopmentVersionNum()) : "");
+  }
+
+  /**
+   * Print the processor version to the command line.
+   *
+   * @param argv command line arguments, unused.
+   */
+  public static void main(String argv[])
+  {
+    System.out.println(getVersion());
+  }
+
+  /**
+   * Name of product
+   */
+  public static String getProduct()
+  {
+    return "standard-taglib";
+  }
+
+  /**
+   * Major version number.
+   * Version number. This changes only when there is a
+   *          significant, externally apparent enhancement from
+   *          the previous release. 'n' represents the n'th
+   *          version.
+   *
+   *          Clients should carefully consider the implications
+   *          of new versions as external interfaces and behaviour
+   *          may have changed.
+   */
+  public static int getMajorVersionNum()
+  {
+      return 1;
+  }
+
+  /**
+   * Release Number.
+   * Release number. This changes when:
+   *            -  a new set of functionality is to be added, eg,
+   *               implementation of a new W3C specification.
+   *            -  API or behaviour change.
+   *            -  its designated as a reference release.
+   */
+  public static int getReleaseVersionNum()
+  {
+    return 1;
+  }
+
+  /**
+   * Maintenance Drop Number.
+   * Optional identifier used to designate maintenance
+   *          drop applied to a specific release and contains
+   *          fixes for defects reported. It maintains compatibility
+   *          with the release and contains no API changes.
+   *          When missing, it designates the final and complete
+   *          development drop for a release.
+   */
+  public static int getMaintenanceVersionNum()
+  {
+    return 2;
+  }
+
+  /**
+   * Development Drop Number.
+   * Optional identifier designates development drop of
+   *          a specific release. D01 is the first development drop
+   *          of a new release.
+   *
+   *          Development drops are works in progress towards a
+   *          compeleted, final release. A specific development drop
+   *          may not completely implement all aspects of a new
+   *          feature, which may take several development drops to
+   *          complete. At the point of the final drop for the
+   *          release, the D suffix will be omitted.
+   *
+   *          Each 'D' drops can contain functional enhancements as
+   *          well as defect fixes. 'D' drops may not be as stable as
+   *          the final releases.
+   */
+  public static int getDevelopmentVersionNum()
+  {
+    return 0;
+  }
+}
diff --git a/standard/src/org/apache/taglibs/standard/extra/spath/ASCII_CharStream.java b/standard/src/org/apache/taglibs/standard/extra/spath/ASCII_CharStream.java
new file mode 100644
index 0000000..ae623c3
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/extra/spath/ASCII_CharStream.java
@@ -0,0 +1,377 @@
+/* Generated By:JavaCC: Do not edit this line. ASCII_CharStream.java Version 0.7pre6 */
+package org.apache.taglibs.standard.extra.spath;
+
+/**
+ * An implementation of interface CharStream, where the stream is assumed to
+ * contain only ASCII characters (without unicode processing).
+ */
+
+public final class ASCII_CharStream
+{
+  public static final boolean staticFlag = false;
+  int bufsize;
+  int available;
+  int tokenBegin;
+  public int bufpos = -1;
+  private int bufline[];
+  private int bufcolumn[];
+
+  private int column = 0;
+  private int line = 1;
+
+  private boolean prevCharIsCR = false;
+  private boolean prevCharIsLF = false;
+
+  private java.io.Reader inputStream;
+
+  private char[] buffer;
+  private int maxNextCharInd = 0;
+  private int inBuf = 0;
+
+  private final void ExpandBuff(boolean wrapAround)
+  {
+     char[] newbuffer = new char[bufsize + 2048];
+     int newbufline[] = new int[bufsize + 2048];
+     int newbufcolumn[] = new int[bufsize + 2048];
+
+     try
+     {
+        if (wrapAround)
+        {
+           System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
+           System.arraycopy(buffer, 0, newbuffer,
+                                             bufsize - tokenBegin, bufpos);
+           buffer = newbuffer;
+
+           System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin);
+           System.arraycopy(bufline, 0, newbufline, bufsize - tokenBegin, bufpos);
+           bufline = newbufline;
+
+           System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin);
+           System.arraycopy(bufcolumn, 0, newbufcolumn, bufsize - tokenBegin, bufpos);
+           bufcolumn = newbufcolumn;
+
+           maxNextCharInd = (bufpos += (bufsize - tokenBegin));
+        }
+        else
+        {
+           System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
+           buffer = newbuffer;
+
+           System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin);
+           bufline = newbufline;
+
+           System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin);
+           bufcolumn = newbufcolumn;
+
+           maxNextCharInd = (bufpos -= tokenBegin);
+        }
+     }
+     catch (Throwable t)
+     {
+        throw new Error(t.getMessage());
+     }
+
+
+     bufsize += 2048;
+     available = bufsize;
+     tokenBegin = 0;
+  }
+
+  private final void FillBuff() throws java.io.IOException
+  {
+     if (maxNextCharInd == available)
+     {
+        if (available == bufsize)
+        {
+           if (tokenBegin > 2048)
+           {
+              bufpos = maxNextCharInd = 0;
+              available = tokenBegin;
+           }
+           else if (tokenBegin < 0)
+              bufpos = maxNextCharInd = 0;
+           else
+              ExpandBuff(false);
+        }
+        else if (available > tokenBegin)
+           available = bufsize;
+        else if ((tokenBegin - available) < 2048)
+           ExpandBuff(true);
+        else
+           available = tokenBegin;
+     }
+
+     int i;
+     try {
+        if ((i = inputStream.read(buffer, maxNextCharInd,
+                                    available - maxNextCharInd)) == -1)
+        {
+           inputStream.close();
+           throw new java.io.IOException();
+        }
+        else
+           maxNextCharInd += i;
+        return;
+     }
+     catch(java.io.IOException e) {
+        --bufpos;
+        backup(0);
+        if (tokenBegin == -1)
+           tokenBegin = bufpos;
+        throw e;
+     }
+  }
+
+  public final char BeginToken() throws java.io.IOException
+  {
+     tokenBegin = -1;
+     char c = readChar();
+     tokenBegin = bufpos;
+
+     return c;
+  }
+
+  private final void UpdateLineColumn(char c)
+  {
+     column++;
+
+     if (prevCharIsLF)
+     {
+        prevCharIsLF = false;
+        line += (column = 1);
+     }
+     else if (prevCharIsCR)
+     {
+        prevCharIsCR = false;
+        if (c == '\n')
+        {
+           prevCharIsLF = true;
+        }
+        else
+           line += (column = 1);
+     }
+
+     switch (c)
+     {
+        case '\r' :
+           prevCharIsCR = true;
+           break;
+        case '\n' :
+           prevCharIsLF = true;
+           break;
+        case '\t' :
+           column--;
+           column += (8 - (column & 07));
+           break;
+        default :
+           break;
+     }
+
+     bufline[bufpos] = line;
+     bufcolumn[bufpos] = column;
+  }
+
+  public final char readChar() throws java.io.IOException
+  {
+     if (inBuf > 0)
+     {
+        --inBuf;
+        return (char)((char)0xff & buffer[(bufpos == bufsize - 1) ? (bufpos = 0) : ++bufpos]);
+     }
+
+     if (++bufpos >= maxNextCharInd)
+        FillBuff();
+
+     char c = (char)((char)0xff & buffer[bufpos]);
+
+     UpdateLineColumn(c);
+     return (c);
+  }
+
+  /**
+   * @deprecated 
+   * @see #getEndColumn
+   */
+
+  public final int getColumn() {
+     return bufcolumn[bufpos];
+  }
+
+  /**
+   * @deprecated 
+   * @see #getEndLine
+   */
+
+  public final int getLine() {
+     return bufline[bufpos];
+  }
+
+  public final int getEndColumn() {
+     return bufcolumn[bufpos];
+  }
+
+  public final int getEndLine() {
+     return bufline[bufpos];
+  }
+
+  public final int getBeginColumn() {
+     return bufcolumn[tokenBegin];
+  }
+
+  public final int getBeginLine() {
+     return bufline[tokenBegin];
+  }
+
+  public final void backup(int amount) {
+
+    inBuf += amount;
+    if ((bufpos -= amount) < 0)
+       bufpos += bufsize;
+  }
+
+  public ASCII_CharStream(java.io.Reader dstream, int startline,
+  int startcolumn, int buffersize)
+  {
+    inputStream = dstream;
+    line = startline;
+    column = startcolumn - 1;
+
+    available = bufsize = buffersize;
+    buffer = new char[buffersize];
+    bufline = new int[buffersize];
+    bufcolumn = new int[buffersize];
+  }
+
+  public ASCII_CharStream(java.io.Reader dstream, int startline,
+                                                           int startcolumn)
+  {
+     this(dstream, startline, startcolumn, 4096);
+  }
+  public void ReInit(java.io.Reader dstream, int startline,
+  int startcolumn, int buffersize)
+  {
+    inputStream = dstream;
+    line = startline;
+    column = startcolumn - 1;
+
+    if (buffer == null || buffersize != buffer.length)
+    {
+      available = bufsize = buffersize;
+      buffer = new char[buffersize];
+      bufline = new int[buffersize];
+      bufcolumn = new int[buffersize];
+    }
+    prevCharIsLF = prevCharIsCR = false;
+    tokenBegin = inBuf = maxNextCharInd = 0;
+    bufpos = -1;
+  }
+
+  public void ReInit(java.io.Reader dstream, int startline,
+                                                           int startcolumn)
+  {
+     ReInit(dstream, startline, startcolumn, 4096);
+  }
+  public ASCII_CharStream(java.io.InputStream dstream, int startline,
+  int startcolumn, int buffersize)
+  {
+     this(new java.io.InputStreamReader(dstream), startline, startcolumn, 4096);
+  }
+
+  public ASCII_CharStream(java.io.InputStream dstream, int startline,
+                                                           int startcolumn)
+  {
+     this(dstream, startline, startcolumn, 4096);
+  }
+
+  public void ReInit(java.io.InputStream dstream, int startline,
+  int startcolumn, int buffersize)
+  {
+     ReInit(new java.io.InputStreamReader(dstream), startline, startcolumn, 4096);
+  }
+  public void ReInit(java.io.InputStream dstream, int startline,
+                                                           int startcolumn)
+  {
+     ReInit(dstream, startline, startcolumn, 4096);
+  }
+  public final String GetImage()
+  {
+     if (bufpos >= tokenBegin)
+        return new String(buffer, tokenBegin, bufpos - tokenBegin + 1);
+     else
+        return new String(buffer, tokenBegin, bufsize - tokenBegin) +
+                              new String(buffer, 0, bufpos + 1);
+  }
+
+  public final char[] GetSuffix(int len)
+  {
+     char[] ret = new char[len];
+
+     if ((bufpos + 1) >= len)
+        System.arraycopy(buffer, bufpos - len + 1, ret, 0, len);
+     else
+     {
+        System.arraycopy(buffer, bufsize - (len - bufpos - 1), ret, 0,
+                                                          len - bufpos - 1);
+        System.arraycopy(buffer, 0, ret, len - bufpos - 1, bufpos + 1);
+     }
+
+     return ret;
+  }
+
+  public void Done()
+  {
+     buffer = null;
+     bufline = null;
+     bufcolumn = null;
+  }
+
+  /**
+   * Method to adjust line and column numbers for the start of a token.<BR>
+   */
+  public void adjustBeginLineColumn(int newLine, int newCol)
+  {
+     int start = tokenBegin;
+     int len;
+
+     if (bufpos >= tokenBegin)
+     {
+        len = bufpos - tokenBegin + inBuf + 1;
+     }
+     else
+     {
+        len = bufsize - tokenBegin + bufpos + 1 + inBuf;
+     }
+
+     int i = 0, j = 0, k = 0;
+     int nextColDiff = 0, columnDiff = 0;
+
+     while (i < len &&
+            bufline[j = start % bufsize] == bufline[k = ++start % bufsize])
+     {
+        bufline[j] = newLine;
+        nextColDiff = columnDiff + bufcolumn[k] - bufcolumn[j];
+        bufcolumn[j] = newCol + columnDiff;
+        columnDiff = nextColDiff;
+        i++;
+     } 
+
+     if (i < len)
+     {
+        bufline[j] = newLine++;
+        bufcolumn[j] = newCol + columnDiff;
+
+        while (i++ < len)
+        {
+           if (bufline[j = start % bufsize] != bufline[++start % bufsize])
+              bufline[j] = newLine++;
+           else
+              bufline[j] = newLine;
+        }
+     }
+
+     line = bufline[j];
+     column = bufcolumn[j];
+  }
+
+}
diff --git a/standard/src/org/apache/taglibs/standard/extra/spath/ASCII_UCodeESC_CharStream.java b/standard/src/org/apache/taglibs/standard/extra/spath/ASCII_UCodeESC_CharStream.java
new file mode 100644
index 0000000..b4e53e7
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/extra/spath/ASCII_UCodeESC_CharStream.java
@@ -0,0 +1,520 @@
+/* Generated By:JavaCC: Do not edit this line. ASCII_UCodeESC_CharStream.java Version 0.7pre6 */
+package org.apache.taglibs.standard.extra.spath;
+
+/**
+ * An implementation of interface CharStream, where the stream is assumed to
+ * contain only ASCII characters (with java-like unicode escape processing).
+ */
+
+public final class ASCII_UCodeESC_CharStream
+{
+  public static final boolean staticFlag = false;
+  static final int hexval(char c) throws java.io.IOException {
+    switch(c)
+    {
+       case '0' :
+          return 0;
+       case '1' :
+          return 1;
+       case '2' :
+          return 2;
+       case '3' :
+          return 3;
+       case '4' :
+          return 4;
+       case '5' :
+          return 5;
+       case '6' :
+          return 6;
+       case '7' :
+          return 7;
+       case '8' :
+          return 8;
+       case '9' :
+          return 9;
+
+       case 'a' :
+       case 'A' :
+          return 10;
+       case 'b' :
+       case 'B' :
+          return 11;
+       case 'c' :
+       case 'C' :
+          return 12;
+       case 'd' :
+       case 'D' :
+          return 13;
+       case 'e' :
+       case 'E' :
+          return 14;
+       case 'f' :
+       case 'F' :
+          return 15;
+    }
+
+    throw new java.io.IOException(); // Should never come here
+  }
+
+  public int bufpos = -1;
+  int bufsize;
+  int available;
+  int tokenBegin;
+  private int bufline[];
+  private int bufcolumn[];
+
+  private int column = 0;
+  private int line = 1;
+
+  private java.io.Reader inputStream;
+
+  private boolean prevCharIsCR = false;
+  private boolean prevCharIsLF = false;
+
+  private char[] nextCharBuf;
+  private char[] buffer;
+  private int maxNextCharInd = 0;
+  private int nextCharInd = -1;
+  private int inBuf = 0;
+
+  private final void ExpandBuff(boolean wrapAround)
+  {
+     char[] newbuffer = new char[bufsize + 2048];
+     int newbufline[] = new int[bufsize + 2048];
+     int newbufcolumn[] = new int[bufsize + 2048];
+
+     try
+     {
+        if (wrapAround)
+        {
+           System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
+           System.arraycopy(buffer, 0, newbuffer,
+                                             bufsize - tokenBegin, bufpos);
+           buffer = newbuffer;
+
+           System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin);
+           System.arraycopy(bufline, 0, newbufline, bufsize - tokenBegin, bufpos);
+           bufline = newbufline;
+
+           System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin);
+           System.arraycopy(bufcolumn, 0, newbufcolumn, bufsize - tokenBegin, bufpos);
+           bufcolumn = newbufcolumn;
+
+           bufpos += (bufsize - tokenBegin);
+        }
+        else
+        {
+           System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
+           buffer = newbuffer;
+
+           System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin);
+           bufline = newbufline;
+
+           System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin);
+           bufcolumn = newbufcolumn;
+
+           bufpos -= tokenBegin;
+        }
+     }
+     catch (Throwable t)
+     {
+        throw new Error(t.getMessage());
+     }
+
+     available = (bufsize += 2048);
+     tokenBegin = 0;
+  }
+
+  private final void FillBuff() throws java.io.IOException
+  {
+     int i;
+     if (maxNextCharInd == 4096)
+        maxNextCharInd = nextCharInd = 0;
+
+     try {
+        if ((i = inputStream.read(nextCharBuf, maxNextCharInd,
+                                            4096 - maxNextCharInd)) == -1)
+        {
+           inputStream.close();
+           throw new java.io.IOException();
+        }
+        else
+           maxNextCharInd += i;
+        return;
+     }
+     catch(java.io.IOException e) {
+        if (bufpos != 0)
+        {
+           --bufpos;
+           backup(0);
+        }
+        else
+        {
+           bufline[bufpos] = line;
+           bufcolumn[bufpos] = column;
+        }
+        throw e;
+     }
+  }
+
+  private final char ReadByte() throws java.io.IOException
+  {
+     if (++nextCharInd >= maxNextCharInd)
+        FillBuff();
+
+     return nextCharBuf[nextCharInd];
+  }
+
+  public final char BeginToken() throws java.io.IOException
+  {     
+     if (inBuf > 0)
+     {
+        --inBuf;
+        return buffer[tokenBegin = (bufpos == bufsize - 1) ? (bufpos = 0)
+                                                           : ++bufpos];
+     }
+
+     tokenBegin = 0;
+     bufpos = -1;
+
+     return readChar();
+  }     
+
+  private final void AdjustBuffSize()
+  {
+     if (available == bufsize)
+     {
+        if (tokenBegin > 2048)
+        {
+           bufpos = 0;
+           available = tokenBegin;
+        }
+        else
+           ExpandBuff(false);
+     }
+     else if (available > tokenBegin)
+        available = bufsize;
+     else if ((tokenBegin - available) < 2048)
+        ExpandBuff(true);
+     else
+        available = tokenBegin;
+  }
+
+  private final void UpdateLineColumn(char c)
+  {
+     column++;
+
+     if (prevCharIsLF)
+     {
+        prevCharIsLF = false;
+        line += (column = 1);
+     }
+     else if (prevCharIsCR)
+     {
+        prevCharIsCR = false;
+        if (c == '\n')
+        {
+           prevCharIsLF = true;
+        }
+        else
+           line += (column = 1);
+     }
+
+     switch (c)
+     {
+        case '\r' :
+           prevCharIsCR = true;
+           break;
+        case '\n' :
+           prevCharIsLF = true;
+           break;
+        case '\t' :
+           column--;
+           column += (8 - (column & 07));
+           break;
+        default :
+           break;
+     }
+
+     bufline[bufpos] = line;
+     bufcolumn[bufpos] = column;
+  }
+
+  public final char readChar() throws java.io.IOException
+  {
+     if (inBuf > 0)
+     {
+        --inBuf;
+        return buffer[(bufpos == bufsize - 1) ? (bufpos = 0) : ++bufpos];
+     }
+
+     char c;
+
+     if (++bufpos == available)
+        AdjustBuffSize();
+
+     if (((buffer[bufpos] = c = (char)((char)0xff & ReadByte())) == '\\'))
+     {
+        UpdateLineColumn(c);
+
+        int backSlashCnt = 1;
+
+        for (;;) // Read all the backslashes
+        {
+           if (++bufpos == available)
+              AdjustBuffSize();
+
+           try
+           {
+              if ((buffer[bufpos] = c = (char)((char)0xff & ReadByte())) != '\\')
+              {
+                 UpdateLineColumn(c);
+                 // found a non-backslash char.
+                 if ((c == 'u') && ((backSlashCnt & 1) == 1))
+                 {
+                    if (--bufpos < 0)
+                       bufpos = bufsize - 1;
+
+                    break;
+                 }
+
+                 backup(backSlashCnt);
+                 return '\\';
+              }
+           }
+           catch(java.io.IOException e)
+           {
+              if (backSlashCnt > 1)
+                 backup(backSlashCnt);
+
+              return '\\';
+           }
+
+           UpdateLineColumn(c);
+           backSlashCnt++;
+        }
+
+        // Here, we have seen an odd number of backslash's followed by a 'u'
+        try
+        {
+           while ((c = (char)((char)0xff & ReadByte())) == 'u')
+              ++column;
+
+           buffer[bufpos] = c = (char)(hexval(c) << 12 |
+                                       hexval((char)((char)0xff & ReadByte())) << 8 |
+                                       hexval((char)((char)0xff & ReadByte())) << 4 |
+                                       hexval((char)((char)0xff & ReadByte())));
+
+           column += 4;
+        }
+        catch(java.io.IOException e)
+        {
+           throw new Error("Invalid escape character at line " + line +
+                                         " column " + column + ".");
+        }
+
+        if (backSlashCnt == 1)
+           return c;
+        else
+        {
+           backup(backSlashCnt - 1);
+           return '\\';
+        }
+     }
+     else
+     {
+        UpdateLineColumn(c);
+        return (c);
+     }
+  }
+
+  /**
+   * @deprecated 
+   * @see #getEndColumn
+   */
+
+  public final int getColumn() {
+     return bufcolumn[bufpos];
+  }
+
+  /**
+   * @deprecated 
+   * @see #getEndLine
+   */
+
+  public final int getLine() {
+     return bufline[bufpos];
+  }
+
+  public final int getEndColumn() {
+     return bufcolumn[bufpos];
+  }
+
+  public final int getEndLine() {
+     return bufline[bufpos];
+  }
+
+  public final int getBeginColumn() {
+     return bufcolumn[tokenBegin];
+  }
+
+  public final int getBeginLine() {
+     return bufline[tokenBegin];
+  }
+
+  public final void backup(int amount) {
+
+    inBuf += amount;
+    if ((bufpos -= amount) < 0)
+       bufpos += bufsize;
+  }
+
+  public ASCII_UCodeESC_CharStream(java.io.Reader dstream,
+                 int startline, int startcolumn, int buffersize)
+  {
+    inputStream = dstream;
+    line = startline;
+    column = startcolumn - 1;
+
+    available = bufsize = buffersize;
+    buffer = new char[buffersize];
+    bufline = new int[buffersize];
+    bufcolumn = new int[buffersize];
+    nextCharBuf = new char[4096];
+  }
+
+  public ASCII_UCodeESC_CharStream(java.io.Reader dstream,
+                                        int startline, int startcolumn)
+  {
+     this(dstream, startline, startcolumn, 4096);
+  }
+  public void ReInit(java.io.Reader dstream,
+                 int startline, int startcolumn, int buffersize)
+  {
+    inputStream = dstream;
+    line = startline;
+    column = startcolumn - 1;
+
+    if (buffer == null || buffersize != buffer.length)
+    {
+      available = bufsize = buffersize;
+      buffer = new char[buffersize];
+      bufline = new int[buffersize];
+      bufcolumn = new int[buffersize];
+      nextCharBuf = new char[4096];
+    }
+    prevCharIsLF = prevCharIsCR = false;
+    tokenBegin = inBuf = maxNextCharInd = 0;
+    nextCharInd = bufpos = -1;
+  }
+
+  public void ReInit(java.io.Reader dstream,
+                                        int startline, int startcolumn)
+  {
+     ReInit(dstream, startline, startcolumn, 4096);
+  }
+  public ASCII_UCodeESC_CharStream(java.io.InputStream dstream, int startline,
+  int startcolumn, int buffersize)
+  {
+     this(new java.io.InputStreamReader(dstream), startline, startcolumn, 4096);
+  }
+
+  public ASCII_UCodeESC_CharStream(java.io.InputStream dstream, int startline,
+                                                           int startcolumn)
+  {
+     this(dstream, startline, startcolumn, 4096);
+  }
+
+  public void ReInit(java.io.InputStream dstream, int startline,
+  int startcolumn, int buffersize)
+  {
+     ReInit(new java.io.InputStreamReader(dstream), startline, startcolumn, 4096);
+  }
+  public void ReInit(java.io.InputStream dstream, int startline,
+                                                           int startcolumn)
+  {
+     ReInit(dstream, startline, startcolumn, 4096);
+  }
+
+  public final String GetImage()
+  {
+     if (bufpos >= tokenBegin)
+        return new String(buffer, tokenBegin, bufpos - tokenBegin + 1);
+     else
+        return new String(buffer, tokenBegin, bufsize - tokenBegin) +
+                              new String(buffer, 0, bufpos + 1);
+  }
+
+  public final char[] GetSuffix(int len)
+  {
+     char[] ret = new char[len];
+
+     if ((bufpos + 1) >= len)
+        System.arraycopy(buffer, bufpos - len + 1, ret, 0, len);
+     else
+     {
+        System.arraycopy(buffer, bufsize - (len - bufpos - 1), ret, 0,
+                                                          len - bufpos - 1);
+        System.arraycopy(buffer, 0, ret, len - bufpos - 1, bufpos + 1);
+     }
+
+     return ret;
+  }
+
+  public void Done()
+  {
+     nextCharBuf = null;
+     buffer = null;
+     bufline = null;
+     bufcolumn = null;
+  }
+
+  /**
+   * Method to adjust line and column numbers for the start of a token.<BR>
+   */
+  public void adjustBeginLineColumn(int newLine, int newCol)
+  {
+     int start = tokenBegin;
+     int len;
+
+     if (bufpos >= tokenBegin)
+     {
+        len = bufpos - tokenBegin + inBuf + 1;
+     }
+     else
+     {
+        len = bufsize - tokenBegin + bufpos + 1 + inBuf;
+     }
+
+     int i = 0, j = 0, k = 0;
+     int nextColDiff = 0, columnDiff = 0;
+
+     while (i < len &&
+            bufline[j = start % bufsize] == bufline[k = ++start % bufsize])
+     {
+        bufline[j] = newLine;
+        nextColDiff = columnDiff + bufcolumn[k] - bufcolumn[j];
+        bufcolumn[j] = newCol + columnDiff;
+        columnDiff = nextColDiff;
+        i++;
+     } 
+
+     if (i < len)
+     {
+        bufline[j] = newLine++;
+        bufcolumn[j] = newCol + columnDiff;
+
+        while (i++ < len)
+        {
+           if (bufline[j = start % bufsize] != bufline[++start % bufsize])
+              bufline[j] = newLine++;
+           else
+              bufline[j] = newLine;
+        }
+     }
+
+     line = bufline[j];
+     column = bufcolumn[j];
+  }
+
+}
diff --git a/standard/src/org/apache/taglibs/standard/extra/spath/AbsolutePath.java b/standard/src/org/apache/taglibs/standard/extra/spath/AbsolutePath.java
new file mode 100644
index 0000000..8b52ca7
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/extra/spath/AbsolutePath.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 1999,2004 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.taglibs.standard.extra.spath;
+
+import java.util.List;
+
+/**
+ * <p>Represents an absolute SPath expression.  Essentially a marker
+ * class.</p>
+ *
+ * @author Shawn Bayern
+ */
+public class AbsolutePath extends Path {
+
+    private boolean all;
+    private RelativePath base;
+
+    /**
+     * Constructs a new AbsolutePath object based on a RelativePath.
+     * An absolute path is the same as a relative path, except that it
+     * begins with '/' or '//' (which one, of those two, can be
+     * determined by the first Step returned from getSteps()).
+     */
+    public AbsolutePath(RelativePath base) {
+	if (base == null)
+	    throw new IllegalArgumentException("non-null base required");
+	this.base = base;
+    }
+
+    // inherit JavaDoc comment
+    public List getSteps() {
+	// simply return our base's Step objects
+	return base.getSteps();
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/extra/spath/AttributePredicate.java b/standard/src/org/apache/taglibs/standard/extra/spath/AttributePredicate.java
new file mode 100644
index 0000000..54a7769
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/extra/spath/AttributePredicate.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 1999,2004 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.taglibs.standard.extra.spath;
+
+
+/**
+ * <p>Represents a predicate expression concerning a single attribute.</p>
+ *
+ * @author Shawn Bayern
+ */
+public class AttributePredicate extends Predicate {
+
+    private String attribute, target;
+
+    /**
+     * Constructs a new AttributePredicate, given an attribute name
+     * and a target literal (with which to test equality).
+     */
+    public AttributePredicate(String attribute, String target) {
+	if (attribute == null)
+	    throw new IllegalArgumentException("non-null attribute needed");
+	if (attribute.indexOf(":") != -1)
+	    throw new IllegalArgumentException(
+		"namespace-qualified attribute names are not currently " +
+		"supported");
+	this.attribute = attribute;
+
+	if (target == null)
+	    throw new IllegalArgumentException("non-null target needed");
+	// strip quotation marks from target
+	this.target = target.substring(1, target.length() - 1);
+    }
+
+    /**
+     * Returns true if the given SAX AttributeList is suitable, given our
+     * attribute name and target; returns false otherwise.
+     */
+    public boolean isMatchingAttribute(org.xml.sax.Attributes a) {
+	String attValue = a.getValue("", attribute);
+	return (attValue != null && attValue.equals(target));
+    }
+} 
diff --git a/standard/src/org/apache/taglibs/standard/extra/spath/ParseException.java b/standard/src/org/apache/taglibs/standard/extra/spath/ParseException.java
new file mode 100644
index 0000000..3e00f5c
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/extra/spath/ParseException.java
@@ -0,0 +1,191 @@
+/* Generated By:JavaCC: Do not edit this line. ParseException.java Version 0.7pre6 */
+package org.apache.taglibs.standard.extra.spath;
+
+/**
+ * This exception is thrown when parse errors are encountered.
+ * You can explicitly create objects of this exception type by
+ * calling the method generateParseException in the generated
+ * parser.
+ *
+ * You can modify this class to customize your error reporting
+ * mechanisms so long as you retain the public fields.
+ */
+public class ParseException extends Exception {
+
+  /**
+   * This constructor is used by the method "generateParseException"
+   * in the generated parser.  Calling this constructor generates
+   * a new object of this type with the fields "currentToken",
+   * "expectedTokenSequences", and "tokenImage" set.  The boolean
+   * flag "specialConstructor" is also set to true to indicate that
+   * this constructor was used to create this object.
+   * This constructor calls its super class with the empty string
+   * to force the "toString" method of parent class "Throwable" to
+   * print the error message in the form:
+   *     ParseException: <result of getMessage>
+   */
+  public ParseException(Token currentTokenVal,
+                        int[][] expectedTokenSequencesVal,
+                        String[] tokenImageVal
+                       )
+  {
+    super("");
+    specialConstructor = true;
+    currentToken = currentTokenVal;
+    expectedTokenSequences = expectedTokenSequencesVal;
+    tokenImage = tokenImageVal;
+  }
+
+  /**
+   * The following constructors are for use by you for whatever
+   * purpose you can think of.  Constructing the exception in this
+   * manner makes the exception behave in the normal way - i.e., as
+   * documented in the class "Throwable".  The fields "errorToken",
+   * "expectedTokenSequences", and "tokenImage" do not contain
+   * relevant information.  The JavaCC generated code does not use
+   * these constructors.
+   */
+
+  public ParseException() {
+    super();
+    specialConstructor = false;
+  }
+
+  public ParseException(String message) {
+    super(message);
+    specialConstructor = false;
+  }
+
+  /**
+   * This variable determines which constructor was used to create
+   * this object and thereby affects the semantics of the
+   * "getMessage" method (see below).
+   */
+  protected boolean specialConstructor;
+
+  /**
+   * This is the last token that has been consumed successfully.  If
+   * this object has been created due to a parse error, the token
+   * followng this token will (therefore) be the first error token.
+   */
+  public Token currentToken;
+
+  /**
+   * Each entry in this array is an array of integers.  Each array
+   * of integers represents a sequence of tokens (by their ordinal
+   * values) that is expected at this point of the parse.
+   */
+  public int[][] expectedTokenSequences;
+
+  /**
+   * This is a reference to the "tokenImage" array of the generated
+   * parser within which the parse error occurred.  This array is
+   * defined in the generated ...Constants interface.
+   */
+  public String[] tokenImage;
+
+  /**
+   * This method has the standard behavior when this object has been
+   * created using the standard constructors.  Otherwise, it uses
+   * "currentToken" and "expectedTokenSequences" to generate a parse
+   * error message and returns it.  If this object has been created
+   * due to a parse error, and you do not catch it (it gets thrown
+   * from the parser), then this method is called during the printing
+   * of the final stack trace, and hence the correct error message
+   * gets displayed.
+   */
+  public String getMessage() {
+    if (!specialConstructor) {
+      return super.getMessage();
+    }
+    String expected = "";
+    int maxSize = 0;
+    for (int i = 0; i < expectedTokenSequences.length; i++) {
+      if (maxSize < expectedTokenSequences[i].length) {
+        maxSize = expectedTokenSequences[i].length;
+      }
+      for (int j = 0; j < expectedTokenSequences[i].length; j++) {
+        expected += tokenImage[expectedTokenSequences[i][j]] + " ";
+      }
+      if (expectedTokenSequences[i][expectedTokenSequences[i].length - 1] != 0) {
+        expected += "...";
+      }
+      expected += eol + "    ";
+    }
+    String retval = "Encountered \"";
+    Token tok = currentToken.next;
+    for (int i = 0; i < maxSize; i++) {
+      if (i != 0) retval += " ";
+      if (tok.kind == 0) {
+        retval += tokenImage[0];
+        break;
+      }
+      retval += add_escapes(tok.image);
+      tok = tok.next; 
+    }
+    retval += "\" at line " + currentToken.next.beginLine + ", column " + currentToken.next.beginColumn + "." + eol;
+    if (expectedTokenSequences.length == 1) {
+      retval += "Was expecting:" + eol + "    ";
+    } else {
+      retval += "Was expecting one of:" + eol + "    ";
+    }
+    retval += expected;
+    return retval;
+  }
+
+  /**
+   * The end of line string for this machine.
+   */
+  protected String eol = System.getProperty("line.separator", "\n");
+ 
+  /**
+   * Used to convert raw characters to their escaped version
+   * when these raw version cannot be used as part of an ASCII
+   * string literal.
+   */
+  protected String add_escapes(String str) {
+      StringBuffer retval = new StringBuffer();
+      char ch;
+      for (int i = 0; i < str.length(); i++) {
+        switch (str.charAt(i))
+        {
+           case 0 :
+              continue;
+           case '\b':
+              retval.append("\\b");
+              continue;
+           case '\t':
+              retval.append("\\t");
+              continue;
+           case '\n':
+              retval.append("\\n");
+              continue;
+           case '\f':
+              retval.append("\\f");
+              continue;
+           case '\r':
+              retval.append("\\r");
+              continue;
+           case '\"':
+              retval.append("\\\"");
+              continue;
+           case '\'':
+              retval.append("\\\'");
+              continue;
+           case '\\':
+              retval.append("\\\\");
+              continue;
+           default:
+              if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) {
+                 String s = "0000" + Integer.toString(ch, 16);
+                 retval.append("\\u" + s.substring(s.length() - 4, s.length()));
+              } else {
+                 retval.append(ch);
+              }
+              continue;
+        }
+      }
+      return retval.toString();
+   }
+
+}
diff --git a/standard/src/org/apache/taglibs/standard/extra/spath/Path.java b/standard/src/org/apache/taglibs/standard/extra/spath/Path.java
new file mode 100644
index 0000000..cd9ccae
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/extra/spath/Path.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 1999,2004 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.taglibs.standard.extra.spath;
+
+import java.util.List;
+
+/**
+ * <p>Represents a simple path (SPath) expression.  A path is an ordered
+ * list of Steps.
+ *
+ * @author Shawn Bayern
+ */
+public abstract class Path {
+
+    /**
+     * Retrives an ordered list of Step objects representing this
+     * expression.  The result is safely modifiable by the caller and
+     * must support List.add(Object) and List.add(int, Object).
+     */
+    public abstract List getSteps();
+
+}
diff --git a/standard/src/org/apache/taglibs/standard/extra/spath/Predicate.java b/standard/src/org/apache/taglibs/standard/extra/spath/Predicate.java
new file mode 100644
index 0000000..8e8c69e
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/extra/spath/Predicate.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 1999,2004 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.taglibs.standard.extra.spath;
+
+
+/**
+ * <p>Represents a simple predicate expression.</p>
+ *
+ * @author Shawn Bayern
+ */
+public abstract class Predicate {
+
+} 
diff --git a/standard/src/org/apache/taglibs/standard/extra/spath/RelativePath.java b/standard/src/org/apache/taglibs/standard/extra/spath/RelativePath.java
new file mode 100644
index 0000000..8100383
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/extra/spath/RelativePath.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 1999,2004 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.taglibs.standard.extra.spath;
+
+import java.util.List;
+import java.util.Vector;
+
+/**
+ * <p>Represents a relative SPath expression.</p>
+ *
+ * @author Shawn Bayern
+ */
+public class RelativePath extends Path {
+
+    private RelativePath next;
+    private Step step;
+
+    /**
+     * Constructs a new RelativePath object, based on a Step and another
+     * (possibly null) RelativePath.  If 'all' is true, then the path
+     * matches all instances of 'next' underneath 'step'; otherwise;
+     * 'next' must be an immediate child of 'step'.
+     */
+    public RelativePath(Step step, RelativePath next) {
+	if (step == null)
+	    throw new IllegalArgumentException("non-null step required");
+	this.step = step;
+	this.next = next;
+    }
+
+    // inherit JavaDoc comment
+    public List getSteps() {
+	// simply merge our 'step' with our 'next'
+	List l;
+	if (next != null)
+	    l = next.getSteps();
+	else
+	    l = new Vector();
+	l.add(0, step);
+	return l;
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/extra/spath/SPathFilter.java b/standard/src/org/apache/taglibs/standard/extra/spath/SPathFilter.java
new file mode 100644
index 0000000..bead698
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/extra/spath/SPathFilter.java
@@ -0,0 +1,272 @@
+/*
+ * Copyright 1999,2004 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.taglibs.standard.extra.spath;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Stack;
+
+import org.apache.xalan.serialize.Serializer;
+import org.apache.xalan.serialize.SerializerFactory;
+import org.apache.xalan.templates.OutputProperties;
+import org.xml.sax.Attributes;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLFilter;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.XMLFilterImpl;
+import org.xml.sax.helpers.XMLReaderFactory;
+
+/**
+ * <p>Filters a SAX stream based on a single supplied SPath
+ * expression.</p>
+ *
+ * @author Shawn Bayern
+ */
+public class SPathFilter extends XMLFilterImpl {
+
+    //*********************************************************************
+    // Protected state
+
+    /** The steps in the SPath expression we use for filtering. */
+    protected List steps;
+
+    //*********************************************************************
+    // Private state in support of filtering
+
+    private int depth;				// depth in parsed document
+    private Stack acceptedDepths;		// depth of acceptance
+    private int excludedDepth;			// depth of exclusion
+
+    private static final boolean DEBUG = false;
+
+    //*********************************************************************
+    // Main method (for testing)
+
+    /** Simple command-line interface, mostly for testing. */
+    public static void main(String args[])
+	    throws ParseException, IOException, SAXException {
+// temporary...
+System.setProperty("org.xml.sax.driver", "org.apache.xerces.parsers.SAXParser");
+
+	// retrieve and parse the expression
+	String expr = args[0];
+	SPathParser s = new SPathParser(expr);
+	Path p = s.expression();
+
+	// construct the appropriate SAX chain
+	// (reader -> us -> serializer)
+	XMLReader r = XMLReaderFactory.createXMLReader();
+	XMLFilter f1 = new SPathFilter(p);
+	XMLFilter f2 = new XMLFilterImpl();
+	f1.setParent(r);
+	f2.setParent(f1);
+	Serializer sz = SerializerFactory.getSerializer
+	    (OutputProperties.getDefaultMethodProperties("xml"));
+	sz.setOutputStream(System.out);
+	f2.setContentHandler(sz.asContentHandler());
+
+	// go!
+	f2.parse(new InputSource(System.in));
+	System.out.println();
+    }
+
+    //*********************************************************************
+    // Constructor and initialization methods
+
+    /** Constructs a new SPathFilter, given a Path. */
+    public SPathFilter(Path path) {
+	init();
+	this.steps = path.getSteps();
+    }
+
+    /** Initializes state used for filtering. */
+    private void init() {
+	depth = 0;
+	excludedDepth = -1;
+	acceptedDepths = new Stack();
+    }
+
+    //*********************************************************************
+    // ContentHandler methods
+
+    // startElement() and endElement() both require and modify filter
+    // state.  They contain and direct the bulk of the filter's operation.
+
+    /** Filter for startElement(). */
+    public void startElement(String uri,
+			     String localName,
+			     String qName,
+			     Attributes a) throws SAXException {
+	// always update the depth
+	depth++;
+
+	// if we're in an accepted section, simply pass through
+	if (isAccepted()) {
+	    getContentHandler().startElement(uri, localName, qName, a);
+	    return;
+	}
+
+	// likewise, if we're excluded, then simply block and return
+	if (isExcluded())
+	    return;
+
+	// now, not accepted or excluded, let's see if we've got a match.
+	// we need to get the appropriate step based on the number of
+	// steps we've previously accepted
+	Step currentStep = (Step) steps.get(acceptedDepths.size());
+
+	if (nodeMatchesStep(currentStep, uri, localName, qName, a)) {
+	    if (DEBUG)
+		System.err.println("*** Progressive match (" + acceptedDepths.size() + "): " + localName);
+	    // new match (progressive)
+	    acceptedDepths.push(new Integer(depth - 1));
+
+	    // is it enough?  give acceptance another chance...
+	    if (isAccepted())
+	        getContentHandler().startElement(uri, localName, qName, a);
+	} else if (!currentStep.isDepthUnlimited()) {
+	    // if the step was preceded by '/' instead of '//', then
+	    // we can't have a match at this node or beneath it
+	    excludedDepth = depth - 1;
+	}
+
+	// nothing left to check; no reason to include node
+        return;
+    }
+
+    /** Filter for endElement(). */
+    public void endElement(String uri, String localName, String qName)
+	    throws SAXException {
+	// reduce the depth
+	depth--;
+
+	if (isExcluded()) {
+	    // determine if exclusion ends with us
+	    if (excludedDepth == depth)
+	        excludedDepth = -1;
+
+	    // either way, we have been excluded, so pass nothing through
+	    return;
+	}
+
+	// if we're excepted (for now), include ourselves...
+	if (isAccepted())
+	    getContentHandler().endElement(uri, localName, qName);
+
+	    if (DEBUG) {
+		System.err.println("***   Closing tag: " + localName);
+		System.err.println("***   acceptedDepths.size(): " + acceptedDepths.size());
+		System.err.println("***   last accepted depth: " + ((Integer)acceptedDepths.peek()).intValue());
+		System.err.println("***   depth: " + depth);
+	    }
+
+	// now, back off if we correspond to a "successful" start tag
+        if (acceptedDepths.size() > 0 &&
+		(((Integer)acceptedDepths.peek()).intValue()) == depth)
+	    acceptedDepths.pop();
+    }
+
+    // The remaining ContentHandler functions require only one bit of
+    // state:  are we in a mode where we pass them through, or does
+    // the current state dictate that we ignore them.  They need no other
+    // information and cannot have any effect on the current state.
+
+    /** Filter for ignoreableWhitespace(). */
+    public void ignorableWhitespace(char[] ch, int start, int length)
+	    throws SAXException {
+	if (isAccepted())
+	    getContentHandler().ignorableWhitespace(ch, start, length);
+    }
+
+    /** Filter for characters(). */
+    public void characters(char[] ch, int start, int length)
+	    throws SAXException {
+	if (isAccepted())
+	    getContentHandler().characters(ch, start, length);
+    }
+
+    /** Filter for startPrefixMapping(). */
+    public void startPrefixMapping(String prefix, String uri)
+	    throws SAXException {
+	if (isAccepted())
+	    getContentHandler().startPrefixMapping(prefix, uri);
+    }
+
+    /** Filter for endPrefixMapping(). */
+    public void endPrefixMapping(String prefix)
+	    throws SAXException {
+	if (isAccepted())
+	    getContentHandler().endPrefixMapping(prefix);
+    }
+
+    /** Filter for processingInstruction(). */
+    public void processingInstruction(String target, String data)
+	    throws SAXException {
+	if (isAccepted())
+	    getContentHandler().processingInstruction(target, data);
+    }
+
+    /** Filter for skippedEntity(). */
+    public void skippedEntity(String name) throws SAXException {
+	if (isAccepted())
+	    getContentHandler().skippedEntity(name);
+    }
+
+    // We reset state in startDocument(), in case we're reused
+    /** Resets state. */
+    public void startDocument() {
+	init();
+    }
+
+    //*********************************************************************
+    // Private utility methods
+
+    public static boolean nodeMatchesStep(Step s,
+				  String uri,
+				  String localName,
+				  String qName,
+				  Attributes a) {
+	// if the name doesn't match, then we've got a loser
+	if (!s.isMatchingName(uri, localName))
+	    return false;
+
+	// it's still in the game; check the predicates
+	List l = s.getPredicates();
+	for (int i = 0; l != null && i < l.size(); i++) {
+	    Predicate p = (Predicate) l.get(i);
+	    if (!(p instanceof AttributePredicate))
+		throw new UnsupportedOperationException
+		    ("only attribute predicates are supported by filter");
+	    if (!((AttributePredicate) p).isMatchingAttribute(a))
+		return false;		// all predicates must match
+	}
+
+	// it's survived
+	return true;
+    }
+
+    /** Returns true if events should be passed through, false otherwise. */
+    private boolean isAccepted() {
+	return (acceptedDepths.size() >= steps.size());
+    }
+
+    /** Returns true if events should be blocked, false otherwise. */
+    private boolean isExcluded() {
+	return (excludedDepth != -1);
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/extra/spath/SPathParser.java b/standard/src/org/apache/taglibs/standard/extra/spath/SPathParser.java
new file mode 100644
index 0000000..c593c41
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/extra/spath/SPathParser.java
@@ -0,0 +1,533 @@
+/* Generated By:JavaCC: Do not edit this line. SPathParser.java */
+package org.apache.taglibs.standard.extra.spath;
+
+import java.util.Vector;
+
+public class SPathParser implements SPathParserConstants {
+
+  /** Simple command-line parser interface, primarily for testing. */
+  public static void main(String args[]) throws ParseException
+  {
+    SPathParser parser = new SPathParser(System.in);
+    Path p = parser.expression();
+    java.util.List l = p.getSteps();
+
+    // output for simple testing
+    System.out.println();
+    if (p instanceof AbsolutePath)
+        System.out.println("Root: /");
+    for (int i = 0; i < l.size(); i++) {
+        Step s = (Step) l.get(i);
+        System.out.print("Step: " + s.getName());
+        if (s.isDepthUnlimited())
+            System.out.print("(*)");
+        System.out.println();
+    }
+  }
+
+  // custom constructor to accept a String
+  public SPathParser(String x) {
+    this(new java.io.StringReader(x));
+  }
+
+//*********************************************************************
+// Actual SPath grammar
+  final public Path expression() throws ParseException {
+  Path expr;
+    if (jj_2_1(2147483647)) {
+      expr = absolutePath();
+      jj_consume_token(0);
+    } else {
+      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+      case QNAME:
+      case NSWILDCARD:
+      case SLASH:
+      case STAR:
+        expr = relativePath();
+        jj_consume_token(0);
+        break;
+      default:
+        jj_la1[0] = jj_gen;
+        jj_consume_token(-1);
+        throw new ParseException();
+      }
+    }
+   {if (true) return expr;}
+    throw new Error("Missing return statement in function");
+  }
+
+  final public AbsolutePath absolutePath() throws ParseException {
+  RelativePath relPath;
+    jj_consume_token(SLASH);
+    relPath = relativePath();
+   {if (true) return new AbsolutePath(relPath);}
+    throw new Error("Missing return statement in function");
+  }
+
+// as an example, we use recursion here to handle a list
+  final public RelativePath relativePath() throws ParseException {
+  RelativePath relPath = null;
+  Step step;
+    step = step();
+    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+    case SLASH:
+      jj_consume_token(SLASH);
+      relPath = relativePath();
+      break;
+    default:
+      jj_la1[1] = jj_gen;
+      ;
+    }
+   {if (true) return new RelativePath(step, relPath);}
+    throw new Error("Missing return statement in function");
+  }
+
+// as an example, we use inline code here to handle a list
+/* 
+ * (i'm doing something perhaps unusual here, including the <SLASH>
+ * as if it were part of the step.  this mechanism for differentiating
+ * '/' from '//' seems most natural, even if it is a bit unconventional.)
+ */
+  final public Step step() throws ParseException {
+  Token slash = null;
+  String nt;
+  Vector pl = null;
+  Predicate p;
+    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+    case SLASH:
+      slash = jj_consume_token(SLASH);
+      break;
+    default:
+      jj_la1[2] = jj_gen;
+      ;
+    }
+    nt = nameTest();
+    label_1:
+    while (true) {
+      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+      case START_BRACKET:
+        ;
+        break;
+      default:
+        jj_la1[3] = jj_gen;
+        break label_1;
+      }
+      p = predicate();
+          if (pl == null) pl = new Vector();
+          pl.add(p);
+    }
+   // if 'slash != null', then we have '//' versus '/'
+   {if (true) return new Step(slash != null, nt, pl);}
+    throw new Error("Missing return statement in function");
+  }
+
+  final public String nameTest() throws ParseException {
+  Token name;
+    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+    case STAR:
+      name = jj_consume_token(STAR);
+      break;
+    case NSWILDCARD:
+      name = jj_consume_token(NSWILDCARD);
+      break;
+    case QNAME:
+      name = jj_consume_token(QNAME);
+      break;
+    default:
+      jj_la1[4] = jj_gen;
+      jj_consume_token(-1);
+      throw new ParseException();
+    }
+   {if (true) return name.toString();}
+    throw new Error("Missing return statement in function");
+  }
+
+  final public Predicate predicate() throws ParseException {
+  Predicate p;
+    jj_consume_token(START_BRACKET);
+    p = attributePredicate();
+    jj_consume_token(END_BRACKET);
+    {if (true) return p;}
+    throw new Error("Missing return statement in function");
+  }
+
+  final public Predicate attributePredicate() throws ParseException {
+  Token attname, target;
+    jj_consume_token(AT);
+    attname = jj_consume_token(QNAME);
+    jj_consume_token(EQUALS);
+    target = jj_consume_token(LITERAL);
+    {if (true) return new AttributePredicate(attname.toString(), target.toString());}
+    throw new Error("Missing return statement in function");
+  }
+
+  final private boolean jj_2_1(int xla) {
+    jj_la = xla; jj_lastpos = jj_scanpos = token;
+    boolean retval = !jj_3_1();
+    jj_save(0, xla);
+    return retval;
+  }
+
+  final private boolean jj_3R_13() {
+    if (jj_scan_token(AT)) return true;
+    if (jj_la == 0 && jj_scanpos == jj_lastpos) return false;
+    if (jj_scan_token(QNAME)) return true;
+    if (jj_la == 0 && jj_scanpos == jj_lastpos) return false;
+    if (jj_scan_token(EQUALS)) return true;
+    if (jj_la == 0 && jj_scanpos == jj_lastpos) return false;
+    if (jj_scan_token(LITERAL)) return true;
+    if (jj_la == 0 && jj_scanpos == jj_lastpos) return false;
+    return false;
+  }
+
+  final private boolean jj_3_1() {
+    if (jj_3R_2()) return true;
+    if (jj_la == 0 && jj_scanpos == jj_lastpos) return false;
+    return false;
+  }
+
+  final private boolean jj_3R_10() {
+    if (jj_scan_token(NSWILDCARD)) return true;
+    if (jj_la == 0 && jj_scanpos == jj_lastpos) return false;
+    return false;
+  }
+
+  final private boolean jj_3R_11() {
+    if (jj_scan_token(QNAME)) return true;
+    if (jj_la == 0 && jj_scanpos == jj_lastpos) return false;
+    return false;
+  }
+
+  final private boolean jj_3R_2() {
+    if (jj_scan_token(SLASH)) return true;
+    if (jj_la == 0 && jj_scanpos == jj_lastpos) return false;
+    if (jj_3R_3()) return true;
+    if (jj_la == 0 && jj_scanpos == jj_lastpos) return false;
+    return false;
+  }
+
+  final private boolean jj_3R_12() {
+    if (jj_scan_token(START_BRACKET)) return true;
+    if (jj_la == 0 && jj_scanpos == jj_lastpos) return false;
+    if (jj_3R_13()) return true;
+    if (jj_la == 0 && jj_scanpos == jj_lastpos) return false;
+    if (jj_scan_token(END_BRACKET)) return true;
+    if (jj_la == 0 && jj_scanpos == jj_lastpos) return false;
+    return false;
+  }
+
+  final private boolean jj_3R_8() {
+    if (jj_3R_12()) return true;
+    if (jj_la == 0 && jj_scanpos == jj_lastpos) return false;
+    return false;
+  }
+
+  final private boolean jj_3R_5() {
+    if (jj_scan_token(SLASH)) return true;
+    if (jj_la == 0 && jj_scanpos == jj_lastpos) return false;
+    if (jj_3R_3()) return true;
+    if (jj_la == 0 && jj_scanpos == jj_lastpos) return false;
+    return false;
+  }
+
+  final private boolean jj_3R_6() {
+    if (jj_scan_token(SLASH)) return true;
+    if (jj_la == 0 && jj_scanpos == jj_lastpos) return false;
+    return false;
+  }
+
+  final private boolean jj_3R_3() {
+    if (jj_3R_4()) return true;
+    if (jj_la == 0 && jj_scanpos == jj_lastpos) return false;
+    Token xsp;
+    xsp = jj_scanpos;
+    if (jj_3R_5()) jj_scanpos = xsp;
+    else if (jj_la == 0 && jj_scanpos == jj_lastpos) return false;
+    return false;
+  }
+
+  final private boolean jj_3R_4() {
+    Token xsp;
+    xsp = jj_scanpos;
+    if (jj_3R_6()) jj_scanpos = xsp;
+    else if (jj_la == 0 && jj_scanpos == jj_lastpos) return false;
+    if (jj_3R_7()) return true;
+    if (jj_la == 0 && jj_scanpos == jj_lastpos) return false;
+    while (true) {
+      xsp = jj_scanpos;
+      if (jj_3R_8()) { jj_scanpos = xsp; break; }
+      if (jj_la == 0 && jj_scanpos == jj_lastpos) return false;
+    }
+    return false;
+  }
+
+  final private boolean jj_3R_9() {
+    if (jj_scan_token(STAR)) return true;
+    if (jj_la == 0 && jj_scanpos == jj_lastpos) return false;
+    return false;
+  }
+
+  final private boolean jj_3R_7() {
+    Token xsp;
+    xsp = jj_scanpos;
+    if (jj_3R_9()) {
+    jj_scanpos = xsp;
+    if (jj_3R_10()) {
+    jj_scanpos = xsp;
+    if (jj_3R_11()) return true;
+    if (jj_la == 0 && jj_scanpos == jj_lastpos) return false;
+    } else if (jj_la == 0 && jj_scanpos == jj_lastpos) return false;
+    } else if (jj_la == 0 && jj_scanpos == jj_lastpos) return false;
+    return false;
+  }
+
+  public SPathParserTokenManager token_source;
+  ASCII_UCodeESC_CharStream jj_input_stream;
+  public Token token, jj_nt;
+  private int jj_ntk;
+  private Token jj_scanpos, jj_lastpos;
+  private int jj_la;
+  public boolean lookingAhead = false;
+  private boolean jj_semLA;
+  private int jj_gen;
+  final private int[] jj_la1 = new int[5];
+  final private int[] jj_la1_0 = {0x6014,0x2000,0x2000,0x10000,0x4014,};
+  final private JJCalls[] jj_2_rtns = new JJCalls[1];
+  private boolean jj_rescan = false;
+  private int jj_gc = 0;
+
+  public SPathParser(java.io.InputStream stream) {
+    jj_input_stream = new ASCII_UCodeESC_CharStream(stream, 1, 1);
+    token_source = new SPathParserTokenManager(jj_input_stream);
+    token = new Token();
+    jj_ntk = -1;
+    jj_gen = 0;
+    for (int i = 0; i < 5; i++) jj_la1[i] = -1;
+    for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
+  }
+
+  public void ReInit(java.io.InputStream stream) {
+    jj_input_stream.ReInit(stream, 1, 1);
+    token_source.ReInit(jj_input_stream);
+    token = new Token();
+    jj_ntk = -1;
+    jj_gen = 0;
+    for (int i = 0; i < 5; i++) jj_la1[i] = -1;
+    for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
+  }
+
+  public SPathParser(java.io.Reader stream) {
+    jj_input_stream = new ASCII_UCodeESC_CharStream(stream, 1, 1);
+    token_source = new SPathParserTokenManager(jj_input_stream);
+    token = new Token();
+    jj_ntk = -1;
+    jj_gen = 0;
+    for (int i = 0; i < 5; i++) jj_la1[i] = -1;
+    for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
+  }
+
+  public void ReInit(java.io.Reader stream) {
+    jj_input_stream.ReInit(stream, 1, 1);
+    token_source.ReInit(jj_input_stream);
+    token = new Token();
+    jj_ntk = -1;
+    jj_gen = 0;
+    for (int i = 0; i < 5; i++) jj_la1[i] = -1;
+    for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
+  }
+
+  public SPathParser(SPathParserTokenManager tm) {
+    token_source = tm;
+    token = new Token();
+    jj_ntk = -1;
+    jj_gen = 0;
+    for (int i = 0; i < 5; i++) jj_la1[i] = -1;
+    for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
+  }
+
+  public void ReInit(SPathParserTokenManager tm) {
+    token_source = tm;
+    token = new Token();
+    jj_ntk = -1;
+    jj_gen = 0;
+    for (int i = 0; i < 5; i++) jj_la1[i] = -1;
+    for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
+  }
+
+  final private Token jj_consume_token(int kind) throws ParseException {
+    Token oldToken;
+    if ((oldToken = token).next != null) token = token.next;
+    else token = token.next = token_source.getNextToken();
+    jj_ntk = -1;
+    if (token.kind == kind) {
+      jj_gen++;
+      if (++jj_gc > 100) {
+        jj_gc = 0;
+        for (int i = 0; i < jj_2_rtns.length; i++) {
+          JJCalls c = jj_2_rtns[i];
+          while (c != null) {
+            if (c.gen < jj_gen) c.first = null;
+            c = c.next;
+          }
+        }
+      }
+      return token;
+    }
+    token = oldToken;
+    jj_kind = kind;
+    throw generateParseException();
+  }
+
+  final private boolean jj_scan_token(int kind) {
+    if (jj_scanpos == jj_lastpos) {
+      jj_la--;
+      if (jj_scanpos.next == null) {
+        jj_lastpos = jj_scanpos = jj_scanpos.next = token_source.getNextToken();
+      } else {
+        jj_lastpos = jj_scanpos = jj_scanpos.next;
+      }
+    } else {
+      jj_scanpos = jj_scanpos.next;
+    }
+    if (jj_rescan) {
+      int i = 0; Token tok = token;
+      while (tok != null && tok != jj_scanpos) { i++; tok = tok.next; }
+      if (tok != null) jj_add_error_token(kind, i);
+    }
+    return (jj_scanpos.kind != kind);
+  }
+
+  final public Token getNextToken() {
+    if (token.next != null) token = token.next;
+    else token = token.next = token_source.getNextToken();
+    jj_ntk = -1;
+    jj_gen++;
+    return token;
+  }
+
+  final public Token getToken(int index) {
+    Token t = lookingAhead ? jj_scanpos : token;
+    for (int i = 0; i < index; i++) {
+      if (t.next != null) t = t.next;
+      else t = t.next = token_source.getNextToken();
+    }
+    return t;
+  }
+
+  final private int jj_ntk() {
+    if ((jj_nt=token.next) == null)
+      return (jj_ntk = (token.next=token_source.getNextToken()).kind);
+    else
+      return (jj_ntk = jj_nt.kind);
+  }
+
+  private java.util.Vector jj_expentries = new java.util.Vector();
+  private int[] jj_expentry;
+  private int jj_kind = -1;
+  private int[] jj_lasttokens = new int[100];
+  private int jj_endpos;
+
+  private void jj_add_error_token(int kind, int pos) {
+    if (pos >= 100) return;
+    if (pos == jj_endpos + 1) {
+      jj_lasttokens[jj_endpos++] = kind;
+    } else if (jj_endpos != 0) {
+      jj_expentry = new int[jj_endpos];
+      for (int i = 0; i < jj_endpos; i++) {
+        jj_expentry[i] = jj_lasttokens[i];
+      }
+      boolean exists = false;
+      for (java.util.Enumeration enum_ = jj_expentries.elements(); enum_.hasMoreElements();) {
+        int[] oldentry = (int[])(enum_.nextElement());
+        if (oldentry.length == jj_expentry.length) {
+          exists = true;
+          for (int i = 0; i < jj_expentry.length; i++) {
+            if (oldentry[i] != jj_expentry[i]) {
+              exists = false;
+              break;
+            }
+          }
+          if (exists) break;
+        }
+      }
+      if (!exists) jj_expentries.addElement(jj_expentry);
+      if (pos != 0) jj_lasttokens[(jj_endpos = pos) - 1] = kind;
+    }
+  }
+
+  final public ParseException generateParseException() {
+    jj_expentries.removeAllElements();
+    boolean[] la1tokens = new boolean[20];
+    for (int i = 0; i < 20; i++) {
+      la1tokens[i] = false;
+    }
+    if (jj_kind >= 0) {
+      la1tokens[jj_kind] = true;
+      jj_kind = -1;
+    }
+    for (int i = 0; i < 5; i++) {
+      if (jj_la1[i] == jj_gen) {
+        for (int j = 0; j < 32; j++) {
+          if ((jj_la1_0[i] & (1<<j)) != 0) {
+            la1tokens[j] = true;
+          }
+        }
+      }
+    }
+    for (int i = 0; i < 20; i++) {
+      if (la1tokens[i]) {
+        jj_expentry = new int[1];
+        jj_expentry[0] = i;
+        jj_expentries.addElement(jj_expentry);
+      }
+    }
+    jj_endpos = 0;
+    jj_rescan_token();
+    jj_add_error_token(0, 0);
+    int[][] exptokseq = new int[jj_expentries.size()][];
+    for (int i = 0; i < jj_expentries.size(); i++) {
+      exptokseq[i] = (int[])jj_expentries.elementAt(i);
+    }
+    return new ParseException(token, exptokseq, tokenImage);
+  }
+
+  final public void enable_tracing() {
+  }
+
+  final public void disable_tracing() {
+  }
+
+  final private void jj_rescan_token() {
+    jj_rescan = true;
+    for (int i = 0; i < 1; i++) {
+      JJCalls p = jj_2_rtns[i];
+      do {
+        if (p.gen > jj_gen) {
+          jj_la = p.arg; jj_lastpos = jj_scanpos = p.first;
+          switch (i) {
+            case 0: jj_3_1(); break;
+          }
+        }
+        p = p.next;
+      } while (p != null);
+    }
+    jj_rescan = false;
+  }
+
+  final private void jj_save(int index, int xla) {
+    JJCalls p = jj_2_rtns[index];
+    while (p.gen > jj_gen) {
+      if (p.next == null) { p = p.next = new JJCalls(); break; }
+      p = p.next;
+    }
+    p.gen = jj_gen + xla - jj_la; p.first = token; p.arg = xla;
+  }
+
+  static final class JJCalls {
+    int gen;
+    Token first;
+    int arg;
+    JJCalls next;
+  }
+
+}
diff --git a/standard/src/org/apache/taglibs/standard/extra/spath/SPathParser.jj b/standard/src/org/apache/taglibs/standard/extra/spath/SPathParser.jj
new file mode 100644
index 0000000..d65af36
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/extra/spath/SPathParser.jj
@@ -0,0 +1,297 @@
+//*********************************************************************
+// SPath grammar (JavaCC)
+// Author: Shawn Bayern
+// For JSTL reference implementation (Apache Jakarta Taglibs)
+
+
+//*********************************************************************
+// Configuration and boilerplate
+
+options {
+  STATIC = false;			// we'll need multiple instances
+  JAVA_UNICODE_ESCAPE = true;		// XML uses Unicode too
+}
+
+PARSER_BEGIN(SPathParser)
+
+package org.apache.taglibs.standard.extra.spath;
+
+import java.util.Vector;
+
+public class SPathParser {
+
+  /** Simple command-line parser interface, primarily for testing. */
+  public static void main(String args[]) throws ParseException
+  {
+    SPathParser parser = new SPathParser(System.in);
+    Path p = parser.expression();
+    java.util.List l = p.getSteps();
+
+    // output for simple testing
+    System.out.println();
+    if (p instanceof AbsolutePath)
+	System.out.println("Root: /");
+    for (int i = 0; i < l.size(); i++) {
+	Step s = (Step) l.get(i);
+	System.out.print("Step: " + s.getName());
+	if (s.isDepthUnlimited())
+	    System.out.print("(*)");
+	System.out.println();
+    }
+  }
+
+  // custom constructor to accept a String
+  public SPathParser(String x) {
+    this(new StringReader(x));
+  }
+
+}
+
+PARSER_END(SPathParser)
+
+//*********************************************************************
+// Literals
+
+TOKEN :
+{
+  < LITERAL:
+      ("\"" ((~["\"","\\"]) | ("\\" ( ["\\","\""] )))* "\"") |
+      ("\'" ((~["\'","\\"]) | ("\\" ( ["\\","\'"] )))* "\'")
+  >
+}
+
+//*********************************************************************
+// Primitive identifiers
+
+TOKEN :
+{
+  < QNAME:  (<NCNAME><COLON>)? (<NCNAME>) >
+ |< NCNAME: (<LETTER> | <UNDERSCORE>) (<NCNAMECHAR>)* >
+ |< NSWILDCARD: (<NCNAME><COLON><STAR>) >
+ |< #NCNAMECHAR: (<LETTER>|<DIGIT>|<DOT>|<DASH>|<UNDERSCORE>|
+		  <COMBINING_CHAR>|<EXTENDER>) >
+ |< #LETTER:
+      (
+	["\u0041"-"\u005A"] | ["\u0061"-"\u007A"] | ["\u00C0"-"\u00D6"] |
+	["\u00D8"-"\u00F6"] | ["\u00F8"-"\u00FF"] | ["\u0100"-"\u0131"] |
+	["\u0134"-"\u013E"] | ["\u0141"-"\u0148"] | ["\u014A"-"\u017E"] |
+	["\u0180"-"\u01C3"] | ["\u01CD"-"\u01F0"] | ["\u01F4"-"\u01F5"] |
+	["\u01FA"-"\u0217"] | ["\u0250"-"\u02A8"] | ["\u02BB"-"\u02C1"] | 
+	"\u0386" | ["\u0388"-"\u038A"] | "\u038C" | ["\u038E"-"\u03A1"] | 
+	["\u03A3"-"\u03CE"] | ["\u03D0"-"\u03D6"] | "\u03DA" | "\u03DC" | 
+	"\u03DE" | "\u03E0" | ["\u03E2"-"\u03F3"] | ["\u0401"-"\u040C"] | 
+	["\u040E"-"\u044F"] | ["\u0451"-"\u045C"] | ["\u045E"-"\u0481"] | 
+	["\u0490"-"\u04C4"] | ["\u04C7"-"\u04C8"] | ["\u04CB"-"\u04CC"] | 
+	["\u04D0"-"\u04EB"] | ["\u04EE"-"\u04F5"] | ["\u04F8"-"\u04F9"] | 
+	["\u0531"-"\u0556"] | "\u0559" | ["\u0561"-"\u0586"] | 
+	["\u05D0"-"\u05EA"] | ["\u05F0"-"\u05F2"] | ["\u0621"-"\u063A"] | 
+	["\u0641"-"\u064A"] | ["\u0671"-"\u06B7"] | ["\u06BA"-"\u06BE"] | 
+	["\u06C0"-"\u06CE"] | ["\u06D0"-"\u06D3"] | "\u06D5" |
+	["\u06E5"-"\u06E6"] | ["\u0905"-"\u0939"] | "\u093D" | 
+	["\u0958"-"\u0961"] | ["\u0985"-"\u098C"] | ["\u098F"-"\u0990"] | 
+	["\u0993"-"\u09A8"] | ["\u09AA"-"\u09B0"] | "\u09B2" | 
+	["\u09B6"-"\u09B9"] | ["\u09DC"-"\u09DD"] | ["\u09DF"-"\u09E1"] | 
+	["\u09F0"-"\u09F1"] | ["\u0A05"-"\u0A0A"] | ["\u0A0F"-"\u0A10"] | 
+	["\u0A13"-"\u0A28"] | ["\u0A2A"-"\u0A30"] | ["\u0A32"-"\u0A33"] | 
+	["\u0A35"-"\u0A36"] | ["\u0A38"-"\u0A39"] | ["\u0A59"-"\u0A5C"] | 
+	"\u0A5E" | ["\u0A72"-"\u0A74"] | ["\u0A85"-"\u0A8B"] | "\u0A8D" | 
+	["\u0A8F"-"\u0A91"] | ["\u0A93"-"\u0AA8"] | ["\u0AAA"-"\u0AB0"] | 
+	["\u0AB2"-"\u0AB3"] | ["\u0AB5"-"\u0AB9"] | "\u0ABD" | "\u0AE0" | 
+	["\u0B05"-"\u0B0C"] | ["\u0B0F"-"\u0B10"] | ["\u0B13"-"\u0B28"] | 
+	["\u0B2A"-"\u0B30"] | ["\u0B32"-"\u0B33"] | ["\u0B36"-"\u0B39"] | 
+	"\u0B3D" | ["\u0B5C"-"\u0B5D"] | ["\u0B5F"-"\u0B61"] | 
+	["\u0B85"-"\u0B8A"] | ["\u0B8E"-"\u0B90"] | ["\u0B92"-"\u0B95"] | 
+	["\u0B99"-"\u0B9A"] | "\u0B9C" | ["\u0B9E"-"\u0B9F"] | 
+	["\u0BA3"-"\u0BA4"] | ["\u0BA8"-"\u0BAA"] | ["\u0BAE"-"\u0BB5"] | 
+	["\u0BB7"-"\u0BB9"] | ["\u0C05"-"\u0C0C"] | ["\u0C0E"-"\u0C10"] | 
+	["\u0C12"-"\u0C28"] | ["\u0C2A"-"\u0C33"] | ["\u0C35"-"\u0C39"] | 
+	["\u0C60"-"\u0C61"] | ["\u0C85"-"\u0C8C"] | ["\u0C8E"-"\u0C90"] | 
+	["\u0C92"-"\u0CA8"] | ["\u0CAA"-"\u0CB3"] | ["\u0CB5"-"\u0CB9"] | 
+	"\u0CDE" | ["\u0CE0"-"\u0CE1"] | ["\u0D05"-"\u0D0C"] | 
+	["\u0D0E"-"\u0D10"] | ["\u0D12"-"\u0D28"] | ["\u0D2A"-"\u0D39"] | 
+	["\u0D60"-"\u0D61"] | ["\u0E01"-"\u0E2E"] | "\u0E30" | 
+	["\u0E32"-"\u0E33"] | ["\u0E40"-"\u0E45"] | ["\u0E81"-"\u0E82"] | 
+	"\u0E84" | ["\u0E87"-"\u0E88"] | "\u0E8A" | "\u0E8D" | 
+	["\u0E94"-"\u0E97"] | ["\u0E99"-"\u0E9F"] | ["\u0EA2"-"\u0EA3"] | 
+	"\u0EA5" | "\u0EA7" | ["\u0EAA"-"\u0EAB"] | ["\u0EAD"-"\u0EAE"] | 
+	"\u0EB0" | ["\u0EB2"-"\u0EB3"] | "\u0EBD" | ["\u0EC0"-"\u0EC4"] | 
+	["\u0F40"-"\u0F47"] | ["\u0F49"-"\u0F69"] | ["\u10A0"-"\u10C5"] | 
+	["\u10D0"-"\u10F6"] | "\u1100" | ["\u1102"-"\u1103"] | 
+	["\u1105"-"\u1107"] | "\u1109" | ["\u110B"-"\u110C"] | 
+	["\u110E"-"\u1112"] | "\u113C" | "\u113E" | "\u1140" | "\u114C" | 
+	"\u114E" | "\u1150" | ["\u1154"-"\u1155"] | "\u1159" | 
+	["\u115F"-"\u1161"] | "\u1163" | "\u1165" | "\u1167" | "\u1169" | 
+	["\u116D"-"\u116E"] | ["\u1172"-"\u1173"] | "\u1175" | 
+	"\u119E" | "\u11A8" | "\u11AB" | ["\u11AE"-"\u11AF"] | 
+	["\u11B7"-"\u11B8"] | "\u11BA" | ["\u11BC"-"\u11C2"] | "\u11EB" | 
+	"\u11F0" | "\u11F9" | ["\u1E00"-"\u1E9B"] | ["\u1EA0"-"\u1EF9"] | 
+	["\u1F00"-"\u1F15"] | ["\u1F18"-"\u1F1D"] | ["\u1F20"-"\u1F45"] | 
+	["\u1F48"-"\u1F4D"] | ["\u1F50"-"\u1F57"] | "\u1F59" | "\u1F5B" | 
+	"\u1F5D" | ["\u1F5F"-"\u1F7D"] | ["\u1F80"-"\u1FB4"] | 
+	["\u1FB6"-"\u1FBC"] | "\u1FBE" | ["\u1FC2"-"\u1FC4"] |
+	["\u1FC6"-"\u1FCC"] | ["\u1FD0"-"\u1FD3"] | ["\u1FD6"-"\u1FDB"] | 
+	["\u1FE0"-"\u1FEC"] | ["\u1FF2"-"\u1FF4"] | ["\u1FF6"-"\u1FFC"] | 
+	"\u2126" | ["\u212A"-"\u212B"] | "\u212E" | ["\u2180"-"\u2182"] | 
+	["\u3041"-"\u3094"] | ["\u30A1"-"\u30FA"] | ["\u3105"-"\u312C"] | 
+	["\uAC00"-"\uD7A3"] | ["\u4E00"-"\u9FA5"] | "\u3007" | 
+	["\u3021"-"\u3029"] 
+      )
+  >
+ |< #DIGIT:
+      (
+	["\u0030"-"\u0039"] | ["\u0660"-"\u0669"] | ["\u06F0"-"\u06F9"] |
+	["\u0966"-"\u096F"] | ["\u09E6"-"\u09EF"] | ["\u0A66"-"\u0A6F"] |
+	["\u0AE6"-"\u0AEF"] | ["\u0B66"-"\u0B6F"] | ["\u0BE7"-"\u0BEF"] |
+	["\u0C66"-"\u0C6F"] | ["\u0CE6"-"\u0CEF"] | ["\u0D66"-"\u0D6F"] |
+	["\u0E50"-"\u0E59"] | ["\u0ED0"-"\u0ED9"] | ["\u0F20"-"\u0F29"]
+      )
+  >
+ |< #COMBINING_CHAR:
+      (
+	["\u0300"-"\u0345"] | ["\u0360"-"\u0361"] | ["\u0483"-"\u0486"] |
+	["\u0591"-"\u05A1"] | ["\u05A3"-"\u05B9"] | ["\u05BB"-"\u05BD"] | 
+	"\u05BF" | ["\u05C1"-"\u05C2"] | "\u05C4" | ["\u064B"-"\u0652"] | 
+	"\u0670" | ["\u06D6"-"\u06DC"] | ["\u06DD"-"\u06DF"] | 
+	["\u06E0"-"\u06E4"] | ["\u06E7"-"\u06E8"] | ["\u06EA"-"\u06ED"] | 
+	["\u0901"-"\u0903"] | "\u093C" | ["\u093E"-"\u094C"] | "\u094D" | 
+	["\u0951"-"\u0954"] | ["\u0962"-"\u0963"] | ["\u0981"-"\u0983"] | 
+	"\u09BC" | "\u09BE" | "\u09BF" | ["\u09C0"-"\u09C4"] | 
+	["\u09C7"-"\u09C8"] | ["\u09CB"-"\u09CD"] | "\u09D7" |
+	["\u09E2"-"\u09E3"] | "\u0A02" | "\u0A3C" | "\u0A3E" | "\u0A3F" | 
+	["\u0A40"-"\u0A42"] | ["\u0A47"-"\u0A48"] | ["\u0A4B"-"\u0A4D"] | 
+	["\u0A70"-"\u0A71"] | ["\u0A81"-"\u0A83"] | "\u0ABC" | 
+	["\u0ABE"-"\u0AC5"] | ["\u0AC7"-"\u0AC9"] | ["\u0ACB"-"\u0ACD"] | 
+	["\u0B01"-"\u0B03"] | "\u0B3C" | ["\u0B3E"-"\u0B43"] | 
+	["\u0B47"-"\u0B48"] | ["\u0B4B"-"\u0B4D"] | ["\u0B56"-"\u0B57"] | 
+	["\u0B82"-"\u0B83"] | ["\u0BBE"-"\u0BC2"] | ["\u0BC6"-"\u0BC8"] | 
+	["\u0BCA"-"\u0BCD"] | "\u0BD7" | ["\u0C01"-"\u0C03"] | 
+	["\u0C3E"-"\u0C44"] | ["\u0C46"-"\u0C48"] | ["\u0C4A"-"\u0C4D"] | 
+	["\u0C55"-"\u0C56"] | ["\u0C82"-"\u0C83"] | ["\u0CBE"-"\u0CC4"] | 
+	["\u0CC6"-"\u0CC8"] | ["\u0CCA"-"\u0CCD"] | ["\u0CD5"-"\u0CD6"] | 
+	["\u0D02"-"\u0D03"] | ["\u0D3E"-"\u0D43"] | ["\u0D46"-"\u0D48"] | 
+	["\u0D4A"-"\u0D4D"] | "\u0D57" | "\u0E31" | ["\u0E34"-"\u0E3A"] | 
+	["\u0E47"-"\u0E4E"] | "\u0EB1" | ["\u0EB4"-"\u0EB9"] | 
+	["\u0EBB"-"\u0EBC"] | ["\u0EC8"-"\u0ECD"] | ["\u0F18"-"\u0F19"] | 
+	"\u0F35" | "\u0F37" | "\u0F39" | "\u0F3E" | "\u0F3F" | 
+	["\u0F71"-"\u0F84"] | ["\u0F86"-"\u0F8B"] | ["\u0F90"-"\u0F95"] | 
+	"\u0F97" | ["\u0F99"-"\u0FAD"] | ["\u0FB1"-"\u0FB7"] | "\u0FB9" | 
+	["\u20D0"-"\u20DC"] | "\u20E1" | ["\u302A"-"\u302F"] | "\u3099" | 
+	"\u309A"
+      ) >
+ |< #EXTENDER:
+      (
+	"\u00B7" | "\u02D0" | "\u02D1" | "\u0387" | "\u0640" | "\u0E46" | 
+	"\u0EC6" | "\u3005" | ["\u3031"-"\u3035"] | ["\u309D"-"\u309E"] | 
+	["\u30FC"-"\u30FE"]
+      ) >
+ |< #UNDERSCORE: "_" >
+ |< #DOT:        "." >
+ |< #DASH:       "-" >
+}
+
+//*********************************************************************
+// Separators
+
+TOKEN :
+{
+  < SLASH: "/" >
+ |< STAR:  "*" >
+ |< COLON: ":" >
+ |< START_BRACKET: "[" >
+ |< END_BRACKET: "]" >
+ |< AT: "@" >
+ |< EQUALS: "=" >
+}
+
+
+//*********************************************************************
+// Actual SPath grammar
+
+Path expression():
+{
+  Path expr;
+}
+{
+ ( LOOKAHEAD(absolutePath()) expr = absolutePath() <EOF> 
+   | expr = relativePath() <EOF> )
+ { return expr; }
+}
+
+AbsolutePath absolutePath():
+{
+  RelativePath relPath;
+}
+{
+ ( <SLASH> relPath = relativePath() )
+ { return new AbsolutePath(relPath); }
+}
+
+// as an example, we use recursion here to handle a list
+RelativePath relativePath():
+{
+  RelativePath relPath = null;
+  Step step;
+}
+{
+ ( step = step() 
+   (<SLASH> relPath = relativePath())? )
+ {
+   return new RelativePath(step, relPath);
+ }
+}
+
+// as an example, we use inline code here to handle a list
+/* 
+ * (i'm doing something perhaps unusual here, including the <SLASH>
+ * as if it were part of the step.  this mechanism for differentiating
+ * '/' from '//' seems most natural, even if it is a bit unconventional.)
+ */
+Step step():
+{
+  Token slash = null;
+  String nt;
+  Vector pl = null;
+  Predicate p;
+}
+{
+ (  (slash = <SLASH>)?
+    nt = nameTest()
+    ( p = predicate()
+	{
+	  if (pl == null) pl = new Vector();
+	  pl.add(p);
+	 }
+    )*
+ )
+ {
+   // if 'slash != null', then we have '//' versus '/'
+   return new Step(slash != null, nt, pl);
+ }
+}
+
+String nameTest():
+{
+  Token name;
+}
+{
+ ( name = <STAR> | name = <NSWILDCARD> | name = <QNAME> )
+ { return name.toString(); }
+}
+
+Predicate predicate():
+{
+  Predicate p;
+}
+{
+  ( <START_BRACKET> p = attributePredicate() <END_BRACKET> )
+  { return p; }
+}
+
+Predicate attributePredicate():
+{
+  Token attname, target;
+}
+{
+  ( <AT> attname = <QNAME> <EQUALS> target = <LITERAL> )
+  { return new AttributePredicate(attname.toString(), target.toString()); }
+}
diff --git a/standard/src/org/apache/taglibs/standard/extra/spath/SPathParserConstants.java b/standard/src/org/apache/taglibs/standard/extra/spath/SPathParserConstants.java
new file mode 100644
index 0000000..5944252
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/extra/spath/SPathParserConstants.java
@@ -0,0 +1,52 @@
+/* Generated By:JavaCC: Do not edit this line. SPathParserConstants.java */
+package org.apache.taglibs.standard.extra.spath;
+
+public interface SPathParserConstants {
+
+  int EOF = 0;
+  int LITERAL = 1;
+  int QNAME = 2;
+  int NCNAME = 3;
+  int NSWILDCARD = 4;
+  int NCNAMECHAR = 5;
+  int LETTER = 6;
+  int DIGIT = 7;
+  int COMBINING_CHAR = 8;
+  int EXTENDER = 9;
+  int UNDERSCORE = 10;
+  int DOT = 11;
+  int DASH = 12;
+  int SLASH = 13;
+  int STAR = 14;
+  int COLON = 15;
+  int START_BRACKET = 16;
+  int END_BRACKET = 17;
+  int AT = 18;
+  int EQUALS = 19;
+
+  int DEFAULT = 0;
+
+  String[] tokenImage = {
+    "<EOF>",
+    "<LITERAL>",
+    "<QNAME>",
+    "<NCNAME>",
+    "<NSWILDCARD>",
+    "<NCNAMECHAR>",
+    "<LETTER>",
+    "<DIGIT>",
+    "<COMBINING_CHAR>",
+    "<EXTENDER>",
+    "\"_\"",
+    "\".\"",
+    "\"-\"",
+    "\"/\"",
+    "\"*\"",
+    "\":\"",
+    "\"[\"",
+    "\"]\"",
+    "\"@\"",
+    "\"=\"",
+  };
+
+}
diff --git a/standard/src/org/apache/taglibs/standard/extra/spath/SPathParserTokenManager.java b/standard/src/org/apache/taglibs/standard/extra/spath/SPathParserTokenManager.java
new file mode 100644
index 0000000..f0aea08
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/extra/spath/SPathParserTokenManager.java
@@ -0,0 +1,683 @@
+/* Generated By:JavaCC: Do not edit this line. SPathParserTokenManager.java */
+package org.apache.taglibs.standard.extra.spath;
+
+public class SPathParserTokenManager implements SPathParserConstants
+{
+private final int jjStopStringLiteralDfa_0(int pos, long active0)
+{
+   switch (pos)
+   {
+      default :
+         return -1;
+   }
+}
+private final int jjStartNfa_0(int pos, long active0)
+{
+   return jjMoveNfa_0(jjStopStringLiteralDfa_0(pos, active0), pos + 1);
+}
+private final int jjStopAtPos(int pos, int kind)
+{
+   jjmatchedKind = kind;
+   jjmatchedPos = pos;
+   return pos + 1;
+}
+private final int jjStartNfaWithStates_0(int pos, int kind, int state)
+{
+   jjmatchedKind = kind;
+   jjmatchedPos = pos;
+   try { curChar = input_stream.readChar(); }
+   catch(java.io.IOException e) { return pos + 1; }
+   return jjMoveNfa_0(state, pos + 1);
+}
+private final int jjMoveStringLiteralDfa0_0()
+{
+   switch(curChar)
+   {
+      case 42:
+         return jjStopAtPos(0, 14);
+      case 47:
+         return jjStopAtPos(0, 13);
+      case 58:
+         return jjStopAtPos(0, 15);
+      case 61:
+         return jjStopAtPos(0, 19);
+      case 64:
+         return jjStopAtPos(0, 18);
+      case 91:
+         return jjStopAtPos(0, 16);
+      case 93:
+         return jjStopAtPos(0, 17);
+      default :
+         return jjMoveNfa_0(0, 0);
+   }
+}
+private final void jjCheckNAdd(int state)
+{
+   if (jjrounds[state] != jjround)
+   {
+      jjstateSet[jjnewStateCnt++] = state;
+      jjrounds[state] = jjround;
+   }
+}
+private final void jjAddStates(int start, int end)
+{
+   do {
+      jjstateSet[jjnewStateCnt++] = jjnextStates[start];
+   } while (start++ != end);
+}
+private final void jjCheckNAddTwoStates(int state1, int state2)
+{
+   jjCheckNAdd(state1);
+   jjCheckNAdd(state2);
+}
+private final void jjCheckNAddStates(int start, int end)
+{
+   do {
+      jjCheckNAdd(jjnextStates[start]);
+   } while (start++ != end);
+}
+private final void jjCheckNAddStates(int start)
+{
+   jjCheckNAdd(jjnextStates[start]);
+   jjCheckNAdd(jjnextStates[start + 1]);
+}
+static final long[] jjbitVec0 = {
+   0xfffffffffffffffeL, 0xffffffffffffffffL, 0xffffffffffffffffL, 0xffffffffffffffffL
+};
+static final long[] jjbitVec2 = {
+   0x0L, 0x0L, 0xffffffffffffffffL, 0xffffffffffffffffL
+};
+static final long[] jjbitVec3 = {
+   0x0L, 0xffffffffffffc000L, 0xfffff0007fffffffL, 0x7fffffL
+};
+static final long[] jjbitVec4 = {
+   0x0L, 0x0L, 0x0L, 0xff7fffffff7fffffL
+};
+static final long[] jjbitVec5 = {
+   0x7ff3ffffffffffffL, 0x7ffffffffffffdfeL, 0xffffffffffffffffL, 0xfc31ffffffffe00fL
+};
+static final long[] jjbitVec6 = {
+   0xffffffL, 0xffffffffffff0000L, 0xf80001ffffffffffL, 0x3L
+};
+static final long[] jjbitVec7 = {
+   0x0L, 0x0L, 0xfffffffbffffd740L, 0xffffd547f7fffL
+};
+static final long[] jjbitVec8 = {
+   0xffffffffffffdffeL, 0xffffffffdffeffffL, 0xffffffffffff0003L, 0x33fcfffffff199fL
+};
+static final long[] jjbitVec9 = {
+   0xfffe000000000000L, 0xfffffffe027fffffL, 0x7fL, 0x707ffffff0000L
+};
+static final long[] jjbitVec10 = {
+   0x7fffffe00000000L, 0xfffe0000000007feL, 0x7cffffffffffffffL, 0x60002f7fffL
+};
+static final long[] jjbitVec11 = {
+   0x23ffffffffffffe0L, 0x3ff000000L, 0x3c5fdfffff99fe0L, 0x30003b0000000L
+};
+static final long[] jjbitVec12 = {
+   0x36dfdfffff987e0L, 0x1c00005e000000L, 0x23edfdfffffbafe0L, 0x100000000L
+};
+static final long[] jjbitVec13 = {
+   0x23cdfdfffff99fe0L, 0x3b0000000L, 0x3bfc718d63dc7e0L, 0x0L
+};
+static final long[] jjbitVec14 = {
+   0x3effdfffffddfe0L, 0x300000000L, 0x3effdfffffddfe0L, 0x340000000L
+};
+static final long[] jjbitVec15 = {
+   0x3fffdfffffddfe0L, 0x300000000L, 0x0L, 0x0L
+};
+static final long[] jjbitVec16 = {
+   0xd7ffffffffffeL, 0x3fL, 0x200d6caefef02596L, 0x1fL
+};
+static final long[] jjbitVec17 = {
+   0x0L, 0x3fffffffeffL, 0x0L, 0x0L
+};
+static final long[] jjbitVec18 = {
+   0x0L, 0x0L, 0xffffffff00000000L, 0x7fffffffff003fL
+};
+static final long[] jjbitVec19 = {
+   0x500000000007daedL, 0x2c62ab82315001L, 0xf580c90040000000L, 0x201080000000007L
+};
+static final long[] jjbitVec20 = {
+   0xffffffffffffffffL, 0xffffffffffffffffL, 0xffffffff0fffffffL, 0x3ffffffffffffffL
+};
+static final long[] jjbitVec21 = {
+   0xffffffff3f3fffffL, 0x3fffffffaaff3f3fL, 0x5fdfffffffffffffL, 0x1fdc1fff0fcf1fdcL
+};
+static final long[] jjbitVec22 = {
+   0x4c4000000000L, 0x0L, 0x7L, 0x0L
+};
+static final long[] jjbitVec23 = {
+   0x3fe00000080L, 0xfffffffffffffffeL, 0xfffffffe001fffffL, 0x7ffffffffffffffL
+};
+static final long[] jjbitVec24 = {
+   0x1fffffffffe0L, 0x0L, 0x0L, 0x0L
+};
+static final long[] jjbitVec25 = {
+   0xffffffffffffffffL, 0xffffffffffffffffL, 0x3fffffffffL, 0x0L
+};
+static final long[] jjbitVec26 = {
+   0xffffffffffffffffL, 0xffffffffffffffffL, 0xfffffffffL, 0x0L
+};
+static final long[] jjbitVec27 = {
+   0x0L, 0x0L, 0x80000000000000L, 0xff7fffffff7fffffL
+};
+static final long[] jjbitVec28 = {
+   0xffffffL, 0xffffffffffff0000L, 0xf80001ffffffffffL, 0x30003L
+};
+static final long[] jjbitVec29 = {
+   0xffffffffffffffffL, 0x30000003fL, 0xfffffffbffffd7c0L, 0xffffd547f7fffL
+};
+static final long[] jjbitVec30 = {
+   0xffffffffffffdffeL, 0xffffffffdffeffffL, 0xffffffffffff007bL, 0x33fcfffffff199fL
+};
+static final long[] jjbitVec31 = {
+   0xfffe000000000000L, 0xfffffffe027fffffL, 0xbbfffffbfffe007fL, 0x707ffffff0016L
+};
+static final long[] jjbitVec32 = {
+   0x7fffffe00000000L, 0xffff03ff0007ffffL, 0x7cffffffffffffffL, 0x3ff3dffffef7fffL
+};
+static final long[] jjbitVec33 = {
+   0xf3ffffffffffffeeL, 0xffcfff1e3fffL, 0xd3c5fdfffff99feeL, 0x3ffcfb080399fL
+};
+static final long[] jjbitVec34 = {
+   0xd36dfdfffff987e4L, 0x1fffc05e003987L, 0xf3edfdfffffbafeeL, 0xffc100003bbfL
+};
+static final long[] jjbitVec35 = {
+   0xf3cdfdfffff99feeL, 0xffc3b0c0398fL, 0xc3bfc718d63dc7ecL, 0xff8000803dc7L
+};
+static final long[] jjbitVec36 = {
+   0xc3effdfffffddfeeL, 0xffc300603ddfL, 0xc3effdfffffddfecL, 0xffc340603ddfL
+};
+static final long[] jjbitVec37 = {
+   0xc3fffdfffffddfecL, 0xffc300803dcfL, 0x0L, 0x0L
+};
+static final long[] jjbitVec38 = {
+   0x7ff7ffffffffffeL, 0x3ff7fffL, 0x3bff6caefef02596L, 0x3ff3f5fL
+};
+static final long[] jjbitVec39 = {
+   0xc2a003ff03000000L, 0xfffe03fffffffeffL, 0x2fe3ffffebf0fdfL, 0x0L
+};
+static final long[] jjbitVec40 = {
+   0x0L, 0x0L, 0x0L, 0x21fff0000L
+};
+static final long[] jjbitVec41 = {
+   0x3efffe000000a0L, 0xfffffffffffffffeL, 0xfffffffe661fffffL, 0x77ffffffffffffffL
+};
+private final int jjMoveNfa_0(int startState, int curPos)
+{
+   int[] nextStates;
+   int startsAt = 0;
+   jjnewStateCnt = 19;
+   int i = 1;
+   jjstateSet[0] = startState;
+   int j, kind = 0x7fffffff;
+   for (;;)
+   {
+      if (++jjround == 0x7fffffff)
+         ReInitRounds();
+      if (curChar < 64)
+      {
+         long l = 1L << curChar;
+         MatchLoop: do
+         {
+            switch(jjstateSet[--i])
+            {
+               case 0:
+                  if (curChar == 39)
+                     jjCheckNAddStates(0, 2);
+                  else if (curChar == 34)
+                     jjCheckNAddStates(3, 5);
+                  break;
+               case 1:
+                  if ((0xfffffffbffffffffL & l) != 0L)
+                     jjCheckNAddStates(3, 5);
+                  break;
+               case 3:
+                  if (curChar == 34)
+                     jjCheckNAddStates(3, 5);
+                  break;
+               case 4:
+                  if (curChar == 34 && kind > 1)
+                     kind = 1;
+                  break;
+               case 5:
+               case 8:
+                  if (curChar == 39)
+                     jjCheckNAddStates(0, 2);
+                  break;
+               case 6:
+                  if ((0xffffff7fffffffffL & l) != 0L)
+                     jjCheckNAddStates(0, 2);
+                  break;
+               case 9:
+                  if (curChar == 39 && kind > 1)
+                     kind = 1;
+                  break;
+               case 11:
+                  if ((0x3ff600000000000L & l) != 0L)
+                     jjAddStates(6, 7);
+                  break;
+               case 12:
+                  if (curChar == 58)
+                     jjstateSet[jjnewStateCnt++] = 13;
+                  break;
+               case 14:
+                  if ((0x3ff600000000000L & l) == 0L)
+                     break;
+                  if (kind > 2)
+                     kind = 2;
+                  jjstateSet[jjnewStateCnt++] = 14;
+                  break;
+               case 15:
+                  if ((0x3ff600000000000L & l) == 0L)
+                     break;
+                  if (kind > 3)
+                     kind = 3;
+                  jjstateSet[jjnewStateCnt++] = 15;
+                  break;
+               case 16:
+                  if ((0x3ff600000000000L & l) != 0L)
+                     jjAddStates(8, 9);
+                  break;
+               case 17:
+                  if (curChar == 58)
+                     jjstateSet[jjnewStateCnt++] = 18;
+                  break;
+               case 18:
+                  if (curChar == 42 && kind > 4)
+                     kind = 4;
+                  break;
+               default : break;
+            }
+         } while(i != startsAt);
+      }
+      else if (curChar < 128)
+      {
+         long l = 1L << (curChar & 077);
+         MatchLoop: do
+         {
+            switch(jjstateSet[--i])
+            {
+               case 0:
+                  if ((0x7fffffe87fffffeL & l) == 0L)
+                     break;
+                  if (kind > 2)
+                     kind = 2;
+                  jjCheckNAddStates(10, 15);
+                  break;
+               case 1:
+                  if ((0xffffffffefffffffL & l) != 0L)
+                     jjCheckNAddStates(3, 5);
+                  break;
+               case 2:
+                  if (curChar == 92)
+                     jjstateSet[jjnewStateCnt++] = 3;
+                  break;
+               case 3:
+                  if (curChar == 92)
+                     jjCheckNAddStates(3, 5);
+                  break;
+               case 6:
+                  if ((0xffffffffefffffffL & l) != 0L)
+                     jjCheckNAddStates(0, 2);
+                  break;
+               case 7:
+                  if (curChar == 92)
+                     jjstateSet[jjnewStateCnt++] = 8;
+                  break;
+               case 8:
+                  if (curChar == 92)
+                     jjCheckNAddStates(0, 2);
+                  break;
+               case 11:
+                  if ((0x7fffffe87fffffeL & l) != 0L)
+                     jjCheckNAddTwoStates(11, 12);
+                  break;
+               case 13:
+               case 14:
+                  if ((0x7fffffe87fffffeL & l) == 0L)
+                     break;
+                  if (kind > 2)
+                     kind = 2;
+                  jjCheckNAdd(14);
+                  break;
+               case 15:
+                  if ((0x7fffffe87fffffeL & l) == 0L)
+                     break;
+                  if (kind > 3)
+                     kind = 3;
+                  jjCheckNAdd(15);
+                  break;
+               case 16:
+                  if ((0x7fffffe87fffffeL & l) != 0L)
+                     jjCheckNAddTwoStates(16, 17);
+                  break;
+               default : break;
+            }
+         } while(i != startsAt);
+      }
+      else
+      {
+         int hiByte = (int)(curChar >> 8);
+         int i1 = hiByte >> 6;
+         long l1 = 1L << (hiByte & 077);
+         int i2 = (curChar & 0xff) >> 6;
+         long l2 = 1L << (curChar & 077);
+         MatchLoop: do
+         {
+            switch(jjstateSet[--i])
+            {
+               case 0:
+                  if (!jjCanMove_1(hiByte, i1, i2, l1, l2))
+                     break;
+                  if (kind > 2)
+                     kind = 2;
+                  jjCheckNAddStates(10, 15);
+                  break;
+               case 1:
+                  if (jjCanMove_0(hiByte, i1, i2, l1, l2))
+                     jjAddStates(3, 5);
+                  break;
+               case 6:
+                  if (jjCanMove_0(hiByte, i1, i2, l1, l2))
+                     jjAddStates(0, 2);
+                  break;
+               case 11:
+                  if (jjCanMove_2(hiByte, i1, i2, l1, l2))
+                     jjCheckNAddTwoStates(11, 12);
+                  break;
+               case 13:
+                  if (!jjCanMove_1(hiByte, i1, i2, l1, l2))
+                     break;
+                  if (kind > 2)
+                     kind = 2;
+                  jjCheckNAdd(14);
+                  break;
+               case 14:
+                  if (!jjCanMove_2(hiByte, i1, i2, l1, l2))
+                     break;
+                  if (kind > 2)
+                     kind = 2;
+                  jjCheckNAdd(14);
+                  break;
+               case 15:
+                  if (!jjCanMove_2(hiByte, i1, i2, l1, l2))
+                     break;
+                  if (kind > 3)
+                     kind = 3;
+                  jjCheckNAdd(15);
+                  break;
+               case 16:
+                  if (jjCanMove_2(hiByte, i1, i2, l1, l2))
+                     jjCheckNAddTwoStates(16, 17);
+                  break;
+               default : break;
+            }
+         } while(i != startsAt);
+      }
+      if (kind != 0x7fffffff)
+      {
+         jjmatchedKind = kind;
+         jjmatchedPos = curPos;
+         kind = 0x7fffffff;
+      }
+      ++curPos;
+      if ((i = jjnewStateCnt) == (startsAt = 19 - (jjnewStateCnt = startsAt)))
+         return curPos;
+      try { curChar = input_stream.readChar(); }
+      catch(java.io.IOException e) { return curPos; }
+   }
+}
+static final int[] jjnextStates = {
+   6, 7, 9, 1, 2, 4, 11, 12, 16, 17, 11, 12, 14, 15, 16, 17, 
+};
+private static final boolean jjCanMove_0(int hiByte, int i1, int i2, long l1, long l2)
+{
+   switch(hiByte)
+   {
+      case 0:
+         return ((jjbitVec2[i2] & l2) != 0L);
+      default : 
+         if ((jjbitVec0[i1] & l1) != 0L)
+            return true;
+         return false;
+   }
+}
+private static final boolean jjCanMove_1(int hiByte, int i1, int i2, long l1, long l2)
+{
+   switch(hiByte)
+   {
+      case 0:
+         return ((jjbitVec4[i2] & l2) != 0L);
+      case 1:
+         return ((jjbitVec5[i2] & l2) != 0L);
+      case 2:
+         return ((jjbitVec6[i2] & l2) != 0L);
+      case 3:
+         return ((jjbitVec7[i2] & l2) != 0L);
+      case 4:
+         return ((jjbitVec8[i2] & l2) != 0L);
+      case 5:
+         return ((jjbitVec9[i2] & l2) != 0L);
+      case 6:
+         return ((jjbitVec10[i2] & l2) != 0L);
+      case 9:
+         return ((jjbitVec11[i2] & l2) != 0L);
+      case 10:
+         return ((jjbitVec12[i2] & l2) != 0L);
+      case 11:
+         return ((jjbitVec13[i2] & l2) != 0L);
+      case 12:
+         return ((jjbitVec14[i2] & l2) != 0L);
+      case 13:
+         return ((jjbitVec15[i2] & l2) != 0L);
+      case 14:
+         return ((jjbitVec16[i2] & l2) != 0L);
+      case 15:
+         return ((jjbitVec17[i2] & l2) != 0L);
+      case 16:
+         return ((jjbitVec18[i2] & l2) != 0L);
+      case 17:
+         return ((jjbitVec19[i2] & l2) != 0L);
+      case 30:
+         return ((jjbitVec20[i2] & l2) != 0L);
+      case 31:
+         return ((jjbitVec21[i2] & l2) != 0L);
+      case 33:
+         return ((jjbitVec22[i2] & l2) != 0L);
+      case 48:
+         return ((jjbitVec23[i2] & l2) != 0L);
+      case 49:
+         return ((jjbitVec24[i2] & l2) != 0L);
+      case 159:
+         return ((jjbitVec25[i2] & l2) != 0L);
+      case 215:
+         return ((jjbitVec26[i2] & l2) != 0L);
+      default : 
+         if ((jjbitVec3[i1] & l1) != 0L)
+            return true;
+         return false;
+   }
+}
+private static final boolean jjCanMove_2(int hiByte, int i1, int i2, long l1, long l2)
+{
+   switch(hiByte)
+   {
+      case 0:
+         return ((jjbitVec27[i2] & l2) != 0L);
+      case 1:
+         return ((jjbitVec5[i2] & l2) != 0L);
+      case 2:
+         return ((jjbitVec28[i2] & l2) != 0L);
+      case 3:
+         return ((jjbitVec29[i2] & l2) != 0L);
+      case 4:
+         return ((jjbitVec30[i2] & l2) != 0L);
+      case 5:
+         return ((jjbitVec31[i2] & l2) != 0L);
+      case 6:
+         return ((jjbitVec32[i2] & l2) != 0L);
+      case 9:
+         return ((jjbitVec33[i2] & l2) != 0L);
+      case 10:
+         return ((jjbitVec34[i2] & l2) != 0L);
+      case 11:
+         return ((jjbitVec35[i2] & l2) != 0L);
+      case 12:
+         return ((jjbitVec36[i2] & l2) != 0L);
+      case 13:
+         return ((jjbitVec37[i2] & l2) != 0L);
+      case 14:
+         return ((jjbitVec38[i2] & l2) != 0L);
+      case 15:
+         return ((jjbitVec39[i2] & l2) != 0L);
+      case 16:
+         return ((jjbitVec18[i2] & l2) != 0L);
+      case 17:
+         return ((jjbitVec19[i2] & l2) != 0L);
+      case 30:
+         return ((jjbitVec20[i2] & l2) != 0L);
+      case 31:
+         return ((jjbitVec21[i2] & l2) != 0L);
+      case 32:
+         return ((jjbitVec40[i2] & l2) != 0L);
+      case 33:
+         return ((jjbitVec22[i2] & l2) != 0L);
+      case 48:
+         return ((jjbitVec41[i2] & l2) != 0L);
+      case 49:
+         return ((jjbitVec24[i2] & l2) != 0L);
+      case 159:
+         return ((jjbitVec25[i2] & l2) != 0L);
+      case 215:
+         return ((jjbitVec26[i2] & l2) != 0L);
+      default : 
+         if ((jjbitVec3[i1] & l1) != 0L)
+            return true;
+         return false;
+   }
+}
+public static final String[] jjstrLiteralImages = {
+"", null, null, null, null, null, null, null, null, null, null, null, null, 
+"\57", "\52", "\72", "\133", "\135", "\100", "\75", };
+public static final String[] lexStateNames = {
+   "DEFAULT", 
+};
+private ASCII_UCodeESC_CharStream input_stream;
+private final int[] jjrounds = new int[19];
+private final int[] jjstateSet = new int[38];
+protected char curChar;
+public SPathParserTokenManager(ASCII_UCodeESC_CharStream stream)
+{
+   if (ASCII_UCodeESC_CharStream.staticFlag)
+      throw new Error("ERROR: Cannot use a static CharStream class with a non-static lexical analyzer.");
+   input_stream = stream;
+}
+public SPathParserTokenManager(ASCII_UCodeESC_CharStream stream, int lexState)
+{
+   this(stream);
+   SwitchTo(lexState);
+}
+public void ReInit(ASCII_UCodeESC_CharStream stream)
+{
+   jjmatchedPos = jjnewStateCnt = 0;
+   curLexState = defaultLexState;
+   input_stream = stream;
+   ReInitRounds();
+}
+private final void ReInitRounds()
+{
+   int i;
+   jjround = 0x80000001;
+   for (i = 19; i-- > 0;)
+      jjrounds[i] = 0x80000000;
+}
+public void ReInit(ASCII_UCodeESC_CharStream stream, int lexState)
+{
+   ReInit(stream);
+   SwitchTo(lexState);
+}
+public void SwitchTo(int lexState)
+{
+   if (lexState >= 1 || lexState < 0)
+      throw new TokenMgrError("Error: Ignoring invalid lexical state : " + lexState + ". State unchanged.", TokenMgrError.INVALID_LEXICAL_STATE);
+   else
+      curLexState = lexState;
+}
+
+private final Token jjFillToken()
+{
+   Token t = Token.newToken(jjmatchedKind);
+   t.kind = jjmatchedKind;
+   String im = jjstrLiteralImages[jjmatchedKind];
+   t.image = (im == null) ? input_stream.GetImage() : im;
+   t.beginLine = input_stream.getBeginLine();
+   t.beginColumn = input_stream.getBeginColumn();
+   t.endLine = input_stream.getEndLine();
+   t.endColumn = input_stream.getEndColumn();
+   return t;
+}
+
+int curLexState = 0;
+int defaultLexState = 0;
+int jjnewStateCnt;
+int jjround;
+int jjmatchedPos;
+int jjmatchedKind;
+
+public final Token getNextToken() 
+{
+  int kind;
+  Token specialToken = null;
+  Token matchedToken;
+  int curPos = 0;
+
+  EOFLoop :
+  for (;;)
+  {   
+   try   
+   {     
+      curChar = input_stream.BeginToken();
+   }     
+   catch(java.io.IOException e)
+   {        
+      jjmatchedKind = 0;
+      matchedToken = jjFillToken();
+      return matchedToken;
+   }
+
+   jjmatchedKind = 0x7fffffff;
+   jjmatchedPos = 0;
+   curPos = jjMoveStringLiteralDfa0_0();
+   if (jjmatchedKind != 0x7fffffff)
+   {
+      if (jjmatchedPos + 1 < curPos)
+         input_stream.backup(curPos - jjmatchedPos - 1);
+         matchedToken = jjFillToken();
+         return matchedToken;
+   }
+   int error_line = input_stream.getEndLine();
+   int error_column = input_stream.getEndColumn();
+   String error_after = null;
+   boolean EOFSeen = false;
+   try { input_stream.readChar(); input_stream.backup(1); }
+   catch (java.io.IOException e1) {
+      EOFSeen = true;
+      error_after = curPos <= 1 ? "" : input_stream.GetImage();
+      if (curChar == '\n' || curChar == '\r') {
+         error_line++;
+         error_column = 0;
+      }
+      else
+         error_column++;
+   }
+   if (!EOFSeen) {
+      input_stream.backup(1);
+      error_after = curPos <= 1 ? "" : input_stream.GetImage();
+   }
+   throw new TokenMgrError(EOFSeen, curLexState, error_line, error_column, error_after, curChar, TokenMgrError.LEXICAL_ERROR);
+  }
+}
+
+}
diff --git a/standard/src/org/apache/taglibs/standard/extra/spath/SPathTag.java b/standard/src/org/apache/taglibs/standard/extra/spath/SPathTag.java
new file mode 100644
index 0000000..179b8ab
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/extra/spath/SPathTag.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.extra.spath;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.JspTagException;
+import javax.servlet.jsp.tagext.TagSupport;
+
+/**
+ * <p>Tag handler that exposes SPath functionality.</p>
+ *
+ * @author Shawn Bayern
+ */
+
+public class SPathTag extends TagSupport {
+
+    //*********************************************************************
+    // Internal state
+
+    private String select;                       // tag attribute
+    private String var;				 // tag attribute
+
+    //*********************************************************************
+    // Construction and initialization
+
+    /**
+     * Constructs a new handler.  As with TagSupport, subclasses should
+     * not provide other constructors and are expected to call the
+     * superclass constructor.
+     */
+    public SPathTag() {
+        super();
+        init();
+    }
+
+    // resets local state
+    private void init() {
+	select = var = null;
+    }
+
+
+    //*********************************************************************
+    // Tag logic
+
+    // applies XPath expression from 'select' and exposes a filter as 'var'
+    public int doStartTag() throws JspException {
+      try {
+	SPathFilter s = new SPathFilter(new SPathParser(select).expression());
+	pageContext.setAttribute(var, s);
+	return SKIP_BODY;
+      } catch (ParseException ex) {
+	throw new JspTagException(ex.toString(), ex);
+      }
+    }
+
+    // Releases any resources we may have (or inherit)
+    public void release() {
+        super.release();
+        init();
+    }
+
+
+    //*********************************************************************
+    // Attribute accessors
+
+    public void setSelect(String select) {
+	this.select = select;
+    }
+
+    public void setVar(String var) {
+	this.var = var;
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/extra/spath/Step.java b/standard/src/org/apache/taglibs/standard/extra/spath/Step.java
new file mode 100644
index 0000000..839b537
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/extra/spath/Step.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright 1999,2004 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.taglibs.standard.extra.spath;
+
+import java.util.List;
+
+/**
+ * <p>Represents a 'step' in an SPath expression.</p>
+ *
+ * @author Shawn Bayern
+ */
+public class Step {
+
+    private boolean depthUnlimited;
+    private String name;
+    private List predicates;
+
+    // record a few things for for efficiency...
+    private String uri, localPart;
+
+    /**
+     * Constructs a new Step object, given a name and a (possibly null)
+     * list of predicates.  A boolean is also passed, indicating
+     * whether this particular Step is relative to the 'descendent-or-self'
+     * axis of the node courrently under consideration.  If true, it is;
+     * if false, then this Step is rooted as a direct child of the node
+     * under consideration.
+     */
+    public Step(boolean depthUnlimited, String name, List predicates) {
+	if (name == null)
+	    throw new IllegalArgumentException("non-null name required");
+	this.depthUnlimited = depthUnlimited;
+	this.name = name;
+	this.predicates = predicates;
+    }
+
+    /**
+     * Returns true if the given name matches the Step object's
+     * name, taking into account the Step object's wildcards; returns
+     * false otherwise.
+     */
+    public boolean isMatchingName(String uri, String localPart) {
+	// check and normalize arguments
+	if (localPart == null)
+	    throw new IllegalArgumentException("need non-null localPart");
+	if (uri != null && uri.equals(""))
+	    uri = null;
+
+	// split name into uri/localPart if we haven't done so already
+	if (this.localPart == null && this.uri == null)
+	    parseStepName();
+
+	// generic wildcard
+	if (this.uri == null && this.localPart.equals("*"))
+	    return true;
+
+	// match will null namespace
+	if (uri == null && this.uri == null
+		&& localPart.equals(this.localPart))
+	    return true;
+
+	if (uri != null && this.uri != null && uri.equals(this.uri)) {
+	    // exact match
+	    if (localPart.equals(this.localPart))
+		return true;
+
+	    // namespace-specific wildcard
+	    if (this.localPart.equals("*"))
+		return true;
+	}
+
+	// no match
+	return false;
+    }
+
+    /** Returns true if the Step's depth is unlimited, false otherwise. */
+    public boolean isDepthUnlimited() {
+	return depthUnlimited;
+    }
+
+    /** Returns the Step's node name. */
+    public String getName() {
+	return name;
+    }
+
+    /** Returns a list of this Step object's predicates. */
+    public List getPredicates() {
+	return predicates;
+    }
+
+    /** Lazily computes some information about our name. */
+    private void parseStepName() {
+	String prefix;
+	int colonIndex = name.indexOf(":");
+
+	if (colonIndex == -1) {
+	    // no colon, so localpart is simply name (even if it's "*")
+	    prefix = null;
+	    localPart = name;
+	} else {
+	    prefix = name.substring(0, colonIndex);
+	    localPart = name.substring(colonIndex + 1);
+	}
+
+	uri = mapPrefix(prefix);
+    }
+
+    /** Returns a URI for the given prefix, given our mappings. */
+    private String mapPrefix(String prefix) {
+	// ability to specify a mapping is, as of yet, unimplemented
+	if (prefix == null)
+	    return null;
+	else
+	    throw new IllegalArgumentException(
+		"unknown prefix '" + prefix + "'");
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/extra/spath/Token.java b/standard/src/org/apache/taglibs/standard/extra/spath/Token.java
new file mode 100644
index 0000000..af47066
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/extra/spath/Token.java
@@ -0,0 +1,81 @@
+/* Generated By:JavaCC: Do not edit this line. Token.java Version 0.7pre3 */
+package org.apache.taglibs.standard.extra.spath;
+
+/**
+ * Describes the input token stream.
+ */
+
+public class Token {
+
+  /**
+   * An integer that describes the kind of this token.  This numbering
+   * system is determined by JavaCCParser, and a table of these numbers is
+   * stored in the file ...Constants.java.
+   */
+  public int kind;
+
+  /**
+   * beginLine and beginColumn describe the position of the first character
+   * of this token; endLine and endColumn describe the position of the
+   * last character of this token.
+   */
+  public int beginLine, beginColumn, endLine, endColumn;
+
+  /**
+   * The string image of the token.
+   */
+  public String image;
+
+  /**
+   * A reference to the next regular (non-special) token from the input
+   * stream.  If this is the last token from the input stream, or if the
+   * token manager has not read tokens beyond this one, this field is
+   * set to null.  This is true only if this token is also a regular
+   * token.  Otherwise, see below for a description of the contents of
+   * this field.
+   */
+  public Token next;
+
+  /**
+   * This field is used to access special tokens that occur prior to this
+   * token, but after the immediately preceding regular (non-special) token.
+   * If there are no such special tokens, this field is set to null.
+   * When there are more than one such special token, this field refers
+   * to the last of these special tokens, which in turn refers to the next
+   * previous special token through its specialToken field, and so on
+   * until the first special token (whose specialToken field is null).
+   * The next fields of special tokens refer to other special tokens that
+   * immediately follow it (without an intervening regular token).  If there
+   * is no such token, this field is null.
+   */
+  public Token specialToken;
+
+  /**
+   * Returns the image.
+   */
+  public final String toString()
+  {
+     return image;
+  }
+
+  /**
+   * Returns a new Token object, by default. However, if you want, you
+   * can create and return subclass objects based on the value of ofKind.
+   * Simply add the cases to the switch for all those special cases.
+   * For example, if you have a subclass of Token called IDToken that
+   * you want to create if ofKind is ID, simlpy add something like :
+   *
+   *    case MyParserConstants.ID : return new IDToken();
+   *
+   * to the following switch statement. Then you can cast matchedToken
+   * variable to the appropriate type and use it in your lexical actions.
+   */
+  public static final Token newToken(int ofKind)
+  {
+     switch(ofKind)
+     {
+       default : return new Token();
+     }
+  }
+
+}
diff --git a/standard/src/org/apache/taglibs/standard/extra/spath/TokenMgrError.java b/standard/src/org/apache/taglibs/standard/extra/spath/TokenMgrError.java
new file mode 100644
index 0000000..0d341b8
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/extra/spath/TokenMgrError.java
@@ -0,0 +1,133 @@
+/* Generated By:JavaCC: Do not edit this line. TokenMgrError.java Version 0.7pre2 */
+package org.apache.taglibs.standard.extra.spath;
+
+public class TokenMgrError extends Error
+{
+   /*
+    * Ordinals for various reasons why an Error of this type can be thrown.
+    */
+
+   /**
+    * Lexical error occured.
+    */
+   static final int LEXICAL_ERROR = 0;
+
+   /**
+    * An attempt wass made to create a second instance of a static token manager.
+    */
+   static final int STATIC_LEXER_ERROR = 1;
+
+   /**
+    * Tried to change to an invalid lexical state.
+    */
+   static final int INVALID_LEXICAL_STATE = 2;
+
+   /**
+    * Detected (and bailed out of) an infinite loop in the token manager.
+    */
+   static final int LOOP_DETECTED = 3;
+
+   /**
+    * Indicates the reason why the exception is thrown. It will have
+    * one of the above 4 values.
+    */
+   int errorCode;
+
+   /**
+    * Replaces unprintable characters by their espaced (or unicode escaped)
+    * equivalents in the given string
+    */
+   protected static final String addEscapes(String str) {
+      StringBuffer retval = new StringBuffer();
+      char ch;
+      for (int i = 0; i < str.length(); i++) {
+        switch (str.charAt(i))
+        {
+           case 0 :
+              continue;
+           case '\b':
+              retval.append("\\b");
+              continue;
+           case '\t':
+              retval.append("\\t");
+              continue;
+           case '\n':
+              retval.append("\\n");
+              continue;
+           case '\f':
+              retval.append("\\f");
+              continue;
+           case '\r':
+              retval.append("\\r");
+              continue;
+           case '\"':
+              retval.append("\\\"");
+              continue;
+           case '\'':
+              retval.append("\\\'");
+              continue;
+           case '\\':
+              retval.append("\\\\");
+              continue;
+           default:
+              if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) {
+                 String s = "0000" + Integer.toString(ch, 16);
+                 retval.append("\\u" + s.substring(s.length() - 4, s.length()));
+              } else {
+                 retval.append(ch);
+              }
+              continue;
+        }
+      }
+      return retval.toString();
+   }
+
+   /**
+    * Returns a detailed message for the Error when it is thrown by the
+    * token manager to indicate a lexical error.
+    * Parameters : 
+    *    EOFSeen     : indicates if EOF caused the lexicl error
+    *    curLexState : lexical state in which this error occured
+    *    errorLine   : line number when the error occured
+    *    errorColumn : column number when the error occured
+    *    errorAfter  : prefix that was seen before this error occured
+    *    curchar     : the offending character
+    * Note: You can customize the lexical error message by modifying this method.
+    */
+   private static final String LexicalError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar) {
+      return("Lexical error at line " +
+           errorLine + ", column " +
+           errorColumn + ".  Encountered: " +
+           (EOFSeen ? "<EOF> " : ("\"" + addEscapes(String.valueOf(curChar)) + "\"") + " (" + (int)curChar + "), ") +
+           "after : \"" + addEscapes(errorAfter) + "\"");
+   }
+
+   /**
+    * You can also modify the body of this method to customize your error messages.
+    * For example, cases like LOOP_DETECTED and INVALID_LEXICAL_STATE are not
+    * of end-users concern, so you can return something like : 
+    *
+    *     "Internal Error : Please file a bug report .... "
+    *
+    * from this method for such cases in the release version of your parser.
+    */
+   public String getMessage() {
+      return super.getMessage();
+   }
+
+   /*
+    * Constructors of various flavors follow.
+    */
+
+   public TokenMgrError() {
+   }
+
+   public TokenMgrError(String message, int reason) {
+      super(message);
+      errorCode = reason;
+   }
+
+   public TokenMgrError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar, int reason) {
+      this(LexicalError(EOFSeen, lexState, errorLine, errorColumn, errorAfter, curChar), reason);
+   }
+}
diff --git a/standard/src/org/apache/taglibs/standard/extra/spath/spath.tld b/standard/src/org/apache/taglibs/standard/extra/spath/spath.tld
new file mode 100644
index 0000000..44f3162
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/extra/spath/spath.tld
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE taglib
+  PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
+  "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
+<taglib>
+  <tlib-version>1.0</tlib-version>
+  <jsp-version>1.2</jsp-version>
+  <short-name>spath</short-name>
+  <uri>http://jakarta.apache.org/taglibs/standard/spath</uri>
+  <display-name>Sample SPath (filter) taglib</display-name>
+  <description>
+    The JSTL RI's hopefully useful example of an XMLFilter.
+  </description>
+
+  <tag>
+    <name>filter</name>
+    <tag-class>org.apache.taglibs.standard.extra.spath.SPathTag</tag-class>
+    <body-content>JSP</body-content>
+    <description>
+      Exposes an XMLFilter that filters an XML document based on a subset
+      of the XPath language.
+    </description>
+    <attribute>
+        <name>select</name>
+        <required>true</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <name>var</name>
+        <required>true</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+</taglib>
diff --git a/standard/src/org/apache/taglibs/standard/functions/Functions.java b/standard/src/org/apache/taglibs/standard/functions/Functions.java
new file mode 100644
index 0000000..6c0731e
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/functions/Functions.java
@@ -0,0 +1,234 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.functions;
+
+import java.lang.reflect.Array;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.StringTokenizer;
+
+import javax.servlet.jsp.JspTagException;
+
+import org.apache.taglibs.standard.resources.Resources;
+import org.apache.taglibs.standard.tag.common.core.Util;
+
+/**
+ * <p>JSTL Functions</p>
+ * 
+ * @author Pierre Delisle
+ */
+
+public class Functions {
+
+    //*********************************************************************
+    // String capitalization
+
+    /**
+     * Converts all of the characters of the input string to upper case.
+     */
+    public static String toUpperCase(String input) {
+        return input.toUpperCase();
+    }
+
+    /**
+     * Converts all of the characters of the input string to lower case.
+     */
+    public static String toLowerCase(String input) {
+        return input.toLowerCase();
+    }
+    
+    //*********************************************************************
+    // Substring processing
+    
+    public static int indexOf(String input, String substring) {
+        if (input == null) input = "";
+        if (substring == null) substring = "";
+        return input.indexOf(substring);
+    }    
+
+    public static boolean contains(String input, String substring) {
+        return indexOf(input, substring) != -1;
+    }    
+
+    public static boolean containsIgnoreCase(String input, String substring) {
+        if (input == null) input = "";
+        if (substring == null) substring = "";        
+        String inputUC = input.toUpperCase();
+        String substringUC = substring.toUpperCase();
+        return indexOf(inputUC, substringUC) != -1;
+    }    
+
+    public static boolean startsWith(String input, String substring) {
+        if (input == null) input = "";
+        if (substring == null) substring = "";
+        return input.startsWith(substring);
+    }    
+        
+    public static boolean endsWith(String input, String substring) {
+        if (input == null) input = "";
+        if (substring == null) substring = "";
+        int index = input.indexOf(substring);
+        if (index == -1) return false;
+        if (index == 0 && substring.length() == 0) return true;
+        return (index == input.length() - substring.length());
+    }  
+    
+    public static String substring(String input, int beginIndex, int endIndex) {
+        if (input == null) input = "";
+        if (beginIndex >= input.length()) return "";
+        if (beginIndex < 0) beginIndex = 0;
+        if (endIndex < 0 || endIndex > input.length()) endIndex = input.length();
+        if (endIndex < beginIndex) return "";
+        return input.substring(beginIndex, endIndex);
+    }    
+    
+    public static String substringAfter(String input, String substring) {
+        if (input == null) input = "";
+        if (input.length() == 0) return "";
+        if (substring == null) substring = "";
+        if (substring.length() == 0) return input;
+        
+        int index = input.indexOf(substring);
+        if (index == -1) {
+            return "";
+        } else {
+            return input.substring(index+substring.length());
+        }
+    }    
+        
+    public static String substringBefore(String input, String substring) {
+        if (input == null) input = "";
+        if (input.length() == 0) return "";
+        if (substring == null) substring = "";
+        if (substring.length() == 0) return "";
+
+        int index = input.indexOf(substring);
+        if (index == -1) {
+            return "";
+        } else {
+            return input.substring(0, index);
+        }
+    }    
+
+    //*********************************************************************
+    // Character replacement
+    
+    public static String escapeXml(String input) {
+        if (input == null) return "";
+        return Util.escapeXml(input);
+    }
+    
+    public static String trim(String input) {
+        if (input == null) return "";
+        return input.trim();
+    }    
+
+    public static String replace(
+    String input, 
+    String substringBefore,
+    String substringAfter) 
+    {
+        if (input == null) input = "";
+        if (input.length() == 0) return "";
+        if (substringBefore == null) substringBefore = "";
+        if (substringBefore.length() == 0) return input;
+                
+        StringBuffer buf = new StringBuffer(input.length());
+        int startIndex = 0;
+        int index;
+        while ((index = input.indexOf(substringBefore, startIndex)) != -1) {
+            buf.append(input.substring(startIndex, index)).append(substringAfter);
+            startIndex = index + substringBefore.length();
+        }
+        return buf.append(input.substring(startIndex)).toString();
+    }
+    
+    public static String[] split(
+    String input, 
+    String delimiters) 
+    {
+        String[] array;
+        if (input == null) input = "";
+        if (input.length() == 0) {
+            array = new String[1];
+            array[0] = "";
+            return array;
+        }
+        
+        if (delimiters == null) delimiters = "";
+
+        StringTokenizer tok = new StringTokenizer(input, delimiters);
+        int count = tok.countTokens();
+        array = new String[count];
+        int i = 0;
+        while (tok.hasMoreTokens()) {
+            array[i++] = tok.nextToken();
+        }
+        return array;
+    }        
+        
+    //*********************************************************************
+    // Collections processing
+    
+    public static int length(Object obj) throws JspTagException {
+        if (obj == null) return 0;  
+        
+        if (obj instanceof String) return ((String)obj).length();
+        if (obj instanceof Collection) return ((Collection)obj).size();
+        if (obj instanceof Map) return ((Map)obj).size();
+        
+        int count = 0;
+        if (obj instanceof Iterator) {
+            Iterator iter = (Iterator)obj;
+            count = 0;
+            while (iter.hasNext()) {
+                count++;
+                iter.next();
+            }
+            return count;
+        }            
+        if (obj instanceof Enumeration) {
+            Enumeration enum_ = (Enumeration)obj;
+            count = 0;
+            while (enum_.hasMoreElements()) {
+                count++;
+                enum_.nextElement();
+            }
+            return count;
+        }
+        try {
+            count = Array.getLength(obj);
+            return count;
+        } catch (IllegalArgumentException ex) {}
+        throw new JspTagException(Resources.getMessage("FOREACH_BAD_ITEMS"));        
+    }      
+
+    public static String join(String[] array, String separator) {
+        if (array == null) return "";         
+        if (separator == null) separator = "";
+        
+        StringBuffer buf = new StringBuffer();
+        for (int i=0; i<array.length; i++) {
+            buf.append(array[i]);
+            if (i < array.length-1) buf.append(separator);
+        }
+        
+        return buf.toString();
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/AndOperator.java b/standard/src/org/apache/taglibs/standard/lang/jstl/AndOperator.java
new file mode 100644
index 0000000..4bf99c7
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/AndOperator.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl;
+
+/**
+ *
+ * <p>The implementation of the and operator
+ * 
+ * @author Nathan Abramson - Art Technology Group
+ * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: pierred $
+ **/
+
+public class AndOperator
+  extends BinaryOperator
+{
+  //-------------------------------------
+  // Singleton
+  //-------------------------------------
+
+  public static final AndOperator SINGLETON =
+    new AndOperator ();
+
+  //-------------------------------------
+  /**
+   *
+   * Constructor
+   **/
+  public AndOperator ()
+  {
+  }
+
+  //-------------------------------------
+  // Expression methods
+  //-------------------------------------
+  /**
+   *
+   * Returns the symbol representing the operator
+   **/
+  public String getOperatorSymbol ()
+  {
+    return "and";
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Applies the operator to the given value
+   **/
+  public Object apply (Object pLeft,
+		       Object pRight,
+		       Object pContext,
+		       Logger pLogger)
+    throws ELException
+  {
+    // Coerce the values to booleans
+    boolean left = 
+      Coercions.coerceToBoolean (pLeft, pLogger).booleanValue ();
+    boolean right = 
+      Coercions.coerceToBoolean (pRight, pLogger).booleanValue ();
+
+    return PrimitiveObjects.getBoolean (left && right);
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Returns true if evaluation is necessary given the specified Left
+   * value.  The And/OrOperators make use of this
+   **/
+  public boolean shouldEvaluate (Object pLeft)
+  {
+    return
+      (pLeft instanceof Boolean) &&
+      ((Boolean) pLeft).booleanValue () == true;
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Returns true if the operator expects its arguments to be coerced
+   * to Booleans.  The And/Or operators set this to true.
+   **/
+  public boolean shouldCoerceToBoolean ()
+  {
+    return true;
+  }
+
+  //-------------------------------------
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/ArithmeticOperator.java b/standard/src/org/apache/taglibs/standard/lang/jstl/ArithmeticOperator.java
new file mode 100644
index 0000000..20c24f4
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/ArithmeticOperator.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl;
+
+/**
+ *
+ * <p>This is the superclass for all binary arithmetic operators
+ * 
+ * @author Nathan Abramson - Art Technology Group
+ * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: pierred $
+ **/
+
+public abstract class ArithmeticOperator
+  extends BinaryOperator
+{
+  //-------------------------------------
+  /**
+   *
+   * Applies the operator to the given value
+   **/
+  public Object apply (Object pLeft,
+		       Object pRight,
+		       Object pContext,
+		       Logger pLogger)
+    throws ELException
+  {
+    return Coercions.applyArithmeticOperator (pLeft, pRight, this, pLogger);
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Applies the operator to the given double values, returning a double
+   **/
+  public abstract double apply (double pLeft,
+				double pRight,
+				Logger pLogger);
+  
+  //-------------------------------------
+  /**
+   *
+   * Applies the operator to the given double values, returning a double
+   **/
+  public abstract long apply (long pLeft,
+			      long pRight,
+			      Logger pLogger);
+  
+  //-------------------------------------
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/ArraySuffix.java b/standard/src/org/apache/taglibs/standard/lang/jstl/ArraySuffix.java
new file mode 100644
index 0000000..d7c7dd5
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/ArraySuffix.java
@@ -0,0 +1,315 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.InvocationTargetException;
+import java.util.List;
+import java.util.Map;
+
+/**
+ *
+ * <p>Represents an operator that obtains a Map entry, an indexed
+ * value, a property value, or an indexed property value of an object.
+ * The following are the rules for evaluating this operator:
+ *
+ * <ul><pre>
+ * Evaluating a[b] (assuming a.b == a["b"])
+ *   a is null
+ *     return null
+ *   b is null
+ *     return null
+ *   a is Map
+ *     !a.containsKey (b)
+ *       return null
+ *     a.get(b) == null
+ *       return null
+ *     otherwise
+ *       return a.get(b)
+ *   a is List or array
+ *     coerce b to int (using coercion rules)
+ *     coercion couldn't be performed
+ *       error
+ *     a.get(b) or Array.get(a, b) throws ArrayIndexOutOfBoundsException or IndexOutOfBoundsException
+ *       return null
+ *     a.get(b) or Array.get(a, b) throws other exception
+ *       error
+ *     return a.get(b) or Array.get(a, b)
+ * 
+ *   coerce b to String
+ *   b is a readable property of a
+ *     getter throws an exception
+ *       error
+ *     otherwise
+ *       return result of getter call
+ *
+ *   otherwise
+ *     error
+ * </pre></ul>
+ * 
+ * @author Nathan Abramson - Art Technology Group
+ * @author Shawn Bayern
+ * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: pierred $
+ **/
+
+public class ArraySuffix
+  extends ValueSuffix
+{
+  //-------------------------------------
+  // Constants
+  //-------------------------------------
+
+  // Zero-argument array
+  static Object [] sNoArgs = new Object [0];
+
+  //-------------------------------------
+  // Properties
+  //-------------------------------------
+  // property index
+
+  Expression mIndex;
+  public Expression getIndex ()
+  { return mIndex; }
+  public void setIndex (Expression pIndex)
+  { mIndex = pIndex; }
+
+  //-------------------------------------
+  /**
+   *
+   * Constructor
+   **/
+  public ArraySuffix (Expression pIndex)
+  {
+    mIndex = pIndex;
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Gets the value of the index
+   **/
+  Object evaluateIndex (Object pContext,
+			VariableResolver pResolver,
+			Map functions,
+			String defaultPrefix,
+			Logger pLogger)
+    throws ELException
+  {
+    return mIndex.evaluate (pContext, pResolver, functions, defaultPrefix,
+			    pLogger);
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Returns the operator symbol
+   **/
+  String getOperatorSymbol ()
+  {
+    return "[]";
+  }
+
+  //-------------------------------------
+  // ValueSuffix methods
+  //-------------------------------------
+  /**
+   *
+   * Returns the expression in the expression language syntax
+   **/
+  public String getExpressionString ()
+  {
+    return "[" + mIndex.getExpressionString () + "]";
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Evaluates the expression in the given context, operating on the
+   * given value.
+   **/
+  public Object evaluate (Object pValue,
+			  Object pContext,
+			  VariableResolver pResolver,
+			  Map functions,
+			  String defaultPrefix,
+			  Logger pLogger)
+    throws ELException
+  {
+    Object indexVal;
+    String indexStr;
+    BeanInfoProperty property;
+    BeanInfoIndexedProperty ixproperty;
+
+    // Check for null value
+    if (pValue == null) {
+      if (pLogger.isLoggingWarning ()) {
+	pLogger.logWarning 
+	  (Constants.CANT_GET_INDEXED_VALUE_OF_NULL,
+	   getOperatorSymbol ());
+      }
+      return null;
+    }
+
+    // Evaluate the index
+    else if ((indexVal = evaluateIndex (pContext, pResolver,
+					functions, defaultPrefix, pLogger)) == 
+	     null) {
+      if (pLogger.isLoggingWarning ()) {
+	pLogger.logWarning
+	  (Constants.CANT_GET_NULL_INDEX,
+	   getOperatorSymbol ());
+      }
+      return null;
+    }
+
+    // See if it's a Map
+    else if (pValue instanceof Map) {
+      Map val = (Map) pValue;
+      return val.get (indexVal);
+    }
+
+    // See if it's a List or array
+    else if (pValue instanceof List ||
+	     pValue.getClass ().isArray ()) {
+      Integer indexObj = Coercions.coerceToInteger (indexVal, pLogger);
+      if (indexObj == null) {
+	if (pLogger.isLoggingError ()) {
+	  pLogger.logError
+	    (Constants.BAD_INDEX_VALUE,
+	     getOperatorSymbol (),
+	     indexVal.getClass ().getName ());
+	}
+	return null;
+      }
+      else if (pValue instanceof List) {
+	try {
+	  return ((List) pValue).get (indexObj.intValue ());
+	}
+	catch (ArrayIndexOutOfBoundsException exc) {
+	  if (pLogger.isLoggingWarning ()) {
+	    pLogger.logWarning
+	      (Constants.EXCEPTION_ACCESSING_LIST,
+	       exc,
+	       indexObj);
+	  }
+	  return null;
+	}
+	catch (IndexOutOfBoundsException exc) {
+	  if (pLogger.isLoggingWarning ()) {
+	    pLogger.logWarning
+	      (Constants.EXCEPTION_ACCESSING_LIST,
+	       exc,
+	       indexObj);
+	  }
+	  return null;
+	}
+	catch (Exception exc) {
+	  if (pLogger.isLoggingError ()) {
+	    pLogger.logError
+	      (Constants.EXCEPTION_ACCESSING_LIST,
+	       exc,
+	       indexObj);
+	  }
+	  return null;
+	}
+      }
+      else {
+	try {
+	  return Array.get (pValue, indexObj.intValue ());
+	}
+	catch (ArrayIndexOutOfBoundsException exc) {
+	  if (pLogger.isLoggingWarning ()) {
+	    pLogger.logWarning
+	      (Constants.EXCEPTION_ACCESSING_ARRAY,
+	       exc,
+	       indexObj);
+	  }
+	  return null;
+	}
+	catch (IndexOutOfBoundsException exc) {
+	  if (pLogger.isLoggingWarning ()) {
+	    pLogger.logWarning
+	      (Constants.EXCEPTION_ACCESSING_ARRAY,
+	       exc,
+	       indexObj);
+	  }
+	  return null;
+	}
+	catch (Exception exc) {
+	  if (pLogger.isLoggingError ()) {
+	    pLogger.logError
+	      (Constants.EXCEPTION_ACCESSING_ARRAY,
+	       exc,
+	       indexObj);
+	  }
+	  return null;
+	}
+      }
+    }
+
+    // Coerce to a String for property access
+
+    else if ((indexStr = Coercions.coerceToString (indexVal, pLogger)) == 
+	     null) {
+      return null;
+    }
+
+    // Look for a JavaBean property
+    else if ((property = BeanInfoManager.getBeanInfoProperty
+	      (pValue.getClass (),
+	       indexStr,
+	       pLogger)) != null &&
+	     property.getReadMethod () != null) {
+      try {
+	return property.getReadMethod ().invoke (pValue, sNoArgs);
+      }
+      catch (InvocationTargetException exc) {
+	if (pLogger.isLoggingError ()) {
+	  pLogger.logError
+	    (Constants.ERROR_GETTING_PROPERTY,
+	     exc.getTargetException (),
+	     indexStr,
+	     pValue.getClass ().getName ());
+	}
+	return null;
+      }
+      catch (Exception exc) {
+	if (pLogger.isLoggingError ()) {
+	  pLogger.logError
+	    (Constants.ERROR_GETTING_PROPERTY,
+	     exc,
+	     indexStr,
+	     pValue.getClass ().getName ());
+	}
+	return null;
+      }
+    }
+
+    else {
+      if (pLogger.isLoggingError ()) {
+	pLogger.logError
+	  (Constants.CANT_FIND_INDEX,
+	   indexVal,
+	   pValue.getClass ().getName (),
+	   getOperatorSymbol ());
+      }
+      return null;
+    }
+  }
+
+  //-------------------------------------
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/BeanInfoIndexedProperty.java b/standard/src/org/apache/taglibs/standard/lang/jstl/BeanInfoIndexedProperty.java
new file mode 100644
index 0000000..3a84736
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/BeanInfoIndexedProperty.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl;
+
+
+
+import java.beans.IndexedPropertyDescriptor;
+
+import java.beans.PropertyDescriptor;
+
+import java.lang.reflect.Method;
+
+
+
+/**
+
+ *
+
+ * <p>This contains the information for one indexed property in a
+
+ * BeanInfo - IndexedPropertyDescriptor, read method, and write
+
+ * method.  This class is necessary because the read/write methods in
+
+ * the IndexedPropertyDescriptor may not be accessible if the bean
+
+ * given to the introspector is not a public class.  In this case, a
+
+ * publicly accessible version of the method must be found by
+
+ * searching for a public superclass/interface that declares the
+
+ * method (this searching is done by the BeanInfoManager).
+
+ * 
+
+ * @author Nathan Abramson - Art Technology Group
+
+ * @version $Change: 181181 $$DateTime: 2001/06/26 09:55:09 $$Author: pierred $
+
+ **/
+
+
+
+public class BeanInfoIndexedProperty
+
+{
+
+  //-------------------------------------
+
+  // Properties
+
+  //-------------------------------------
+
+  // property readMethod
+
+
+
+  Method mReadMethod;
+
+  public Method getReadMethod ()
+
+  { return mReadMethod; }
+
+
+
+  //-------------------------------------
+
+  // property writeMethod
+
+
+
+  Method mWriteMethod;
+
+  public Method getWriteMethod ()
+
+  { return mWriteMethod; }
+
+
+
+  //-------------------------------------
+
+  // property propertyDescriptor
+
+
+
+  IndexedPropertyDescriptor mIndexedPropertyDescriptor;
+
+  public IndexedPropertyDescriptor getIndexedPropertyDescriptor ()
+
+  { return mIndexedPropertyDescriptor; }
+
+
+
+  //-------------------------------------
+
+  /**
+
+   *
+
+   * Constructor
+
+   **/
+
+  public BeanInfoIndexedProperty 
+
+    (Method pReadMethod,
+
+     Method pWriteMethod,
+
+     IndexedPropertyDescriptor pIndexedPropertyDescriptor)
+
+  {
+
+    mReadMethod = pReadMethod;
+
+    mWriteMethod = pWriteMethod;
+
+    mIndexedPropertyDescriptor = pIndexedPropertyDescriptor;
+
+  }
+
+
+
+  //-------------------------------------
+
+}
+
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/BeanInfoManager.java b/standard/src/org/apache/taglibs/standard/lang/jstl/BeanInfoManager.java
new file mode 100644
index 0000000..a377c58
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/BeanInfoManager.java
@@ -0,0 +1,382 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl;
+
+import java.beans.BeanInfo;
+import java.beans.EventSetDescriptor;
+import java.beans.IndexedPropertyDescriptor;
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ *
+ * <p>Manages the BeanInfo for one class - contains the BeanInfo, and
+ * also a mapping from property name to BeanInfoProperty.  There are
+ * also static methods for accessing the BeanInfoManager for a class -
+ * those mappings are cached permanently so that once the
+ * BeanInfoManager is calculated, it doesn't have to be calculated
+ * again.
+ * 
+ * @author Nathan Abramson - Art Technology Group
+ * @version $Change: 181181 $$DateTime: 2001/06/26 09:55:09 $$Author: pierred $
+ **/
+
+public class BeanInfoManager
+{
+  //-------------------------------------
+  // Properties
+  //-------------------------------------
+  // property beanClass
+
+  Class mBeanClass;
+  public Class getBeanClass ()
+  { return mBeanClass; }
+
+  //-------------------------------------
+  // Member variables
+  //-------------------------------------
+
+  // The BeanInfo
+  BeanInfo mBeanInfo;
+
+  // Mapping from property name to BeanInfoProperty
+  Map mPropertyByName;
+
+  // Mapping from property name to BeanInfoIndexedProperty
+  Map mIndexedPropertyByName;
+
+  // Mapping from event set name to event set descriptor
+  Map mEventSetByName;
+
+  // Flag if this is initialized
+  boolean mInitialized;
+
+  // The global mapping from class to BeanInfoManager
+  static Map mBeanInfoManagerByClass = new HashMap ();
+
+  //-------------------------------------
+  /**
+   *
+   * Constructor
+   **/
+  BeanInfoManager (Class pBeanClass)
+  {
+    mBeanClass = pBeanClass;
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Returns the BeanInfoManager for the specified class
+   **/
+  public static BeanInfoManager getBeanInfoManager (Class pClass)
+  {
+    BeanInfoManager ret = (BeanInfoManager) 
+      mBeanInfoManagerByClass.get (pClass);
+    if (ret == null) {
+      ret = createBeanInfoManager (pClass);
+    }
+    return ret;
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Creates and registers the BeanInfoManager for the given class if
+   * it isn't already registered.
+   **/
+  static synchronized BeanInfoManager createBeanInfoManager (Class pClass)
+  {
+    // Because this method is synchronized statically, the
+    // BeanInfoManager is not initialized at this time (otherwise it
+    // could end up being a bottleneck for the entire system).  It is
+    // put into the map in an uninitialized state.  The first time
+    // someone tries to use it, it will be initialized (with proper
+    // synchronizations in place to make sure it is only initialized
+    // once).
+
+    BeanInfoManager ret = (BeanInfoManager) 
+      mBeanInfoManagerByClass.get (pClass);
+    if (ret == null) {
+      ret = new BeanInfoManager (pClass);
+      mBeanInfoManagerByClass.put (pClass, ret);
+    }
+    return ret;
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Returns the BeanInfoProperty for the specified property in the
+   * given class, or null if not found.
+   **/
+  public static BeanInfoProperty getBeanInfoProperty
+    (Class pClass,
+     String pPropertyName,
+     Logger pLogger)
+    throws ELException
+  {
+    return getBeanInfoManager (pClass).getProperty (pPropertyName, pLogger);
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Returns the BeanInfoIndexedProperty for the specified property in
+   * the given class, or null if not found.
+   **/
+  public static BeanInfoIndexedProperty getBeanInfoIndexedProperty
+    (Class pClass,
+     String pIndexedPropertyName,
+     Logger pLogger)
+    throws ELException
+  {
+    return getBeanInfoManager 
+      (pClass).getIndexedProperty (pIndexedPropertyName, pLogger);
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Makes sure that this class has been initialized, and synchronizes
+   * the initialization if it's required.
+   **/
+  void checkInitialized (Logger pLogger)
+    throws ELException
+  {
+    if (!mInitialized) {
+      synchronized (this) {
+	if (!mInitialized) {
+	  initialize (pLogger);
+	  mInitialized = true;
+	}
+      }
+    }
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Initializes by mapping property names to BeanInfoProperties
+   **/
+  void initialize (Logger pLogger)
+    throws ELException
+  {
+    try {
+      mBeanInfo = Introspector.getBeanInfo (mBeanClass);
+
+      mPropertyByName = new HashMap ();
+      mIndexedPropertyByName = new HashMap ();
+      PropertyDescriptor [] pds = mBeanInfo.getPropertyDescriptors ();
+      for (int i = 0; pds != null && i < pds.length; i++) {
+	// Treat as both an indexed property and a normal property
+	PropertyDescriptor pd = pds [i];
+	if (pd instanceof IndexedPropertyDescriptor) {
+	  IndexedPropertyDescriptor ipd = (IndexedPropertyDescriptor) pd;
+	  Method readMethod = getPublicMethod (ipd.getIndexedReadMethod ());
+	  Method writeMethod = getPublicMethod (ipd.getIndexedWriteMethod ());
+	  BeanInfoIndexedProperty property = new BeanInfoIndexedProperty
+	    (readMethod,
+	     writeMethod,
+	     ipd);
+
+	  mIndexedPropertyByName.put (ipd.getName (), property);
+	}
+
+	Method readMethod = getPublicMethod (pd.getReadMethod ());
+	Method writeMethod = getPublicMethod (pd.getWriteMethod ());
+	BeanInfoProperty property = new BeanInfoProperty
+	  (readMethod,
+	   writeMethod,
+	   pd);
+
+	mPropertyByName.put (pd.getName (), property);
+      }
+
+      mEventSetByName = new HashMap ();
+      EventSetDescriptor [] esds = mBeanInfo.getEventSetDescriptors ();
+      for (int i = 0; esds != null && i < esds.length; i++) {
+	EventSetDescriptor esd = esds [i];
+	mEventSetByName.put (esd.getName (), esd);
+      }
+    }
+    catch (IntrospectionException exc) {
+      if (pLogger.isLoggingWarning ()) {
+	pLogger.logWarning
+	  (Constants.EXCEPTION_GETTING_BEANINFO,
+	   exc,
+	   mBeanClass.getName ());
+      }
+    }
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Returns the BeanInfo for the class
+   **/
+  BeanInfo getBeanInfo (Logger pLogger)
+    throws ELException
+  {
+    checkInitialized (pLogger);
+    return mBeanInfo;
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Returns the BeanInfoProperty for the given property name, or null
+   * if not found.
+   **/
+  public BeanInfoProperty getProperty (String pPropertyName,
+				       Logger pLogger)
+    throws ELException
+  {
+    checkInitialized (pLogger);
+    return (BeanInfoProperty) mPropertyByName.get (pPropertyName);
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Returns the BeanInfoIndexedProperty for the given property name,
+   * or null if not found.
+   **/
+  public BeanInfoIndexedProperty getIndexedProperty 
+    (String pIndexedPropertyName,
+     Logger pLogger)
+    throws ELException
+  {
+    checkInitialized (pLogger);
+    return (BeanInfoIndexedProperty) 
+      mIndexedPropertyByName.get (pIndexedPropertyName);
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Returns the EventSetDescriptor for the given event set name, or
+   * null if not found.
+   **/
+  public EventSetDescriptor getEventSet (String pEventSetName,
+					 Logger pLogger)
+    throws ELException
+  {
+    checkInitialized (pLogger);
+    return (EventSetDescriptor) mEventSetByName.get (pEventSetName);
+  }
+
+  //-------------------------------------
+  // Finding the public version of a method - if a PropertyDescriptor
+  // is obtained for a non-public class that implements a public
+  // interface, the read/write methods will be for the class, and
+  // therefore inaccessible.  To correct this, a version of the same
+  // method must be found in a superclass or interface.
+  //-------------------------------------
+  /**
+   *
+   * Returns a publicly-accessible version of the given method, by
+   * searching for a public declaring class.
+   **/
+  static Method getPublicMethod (Method pMethod)
+  {
+    if (pMethod == null) {
+      return null;
+    }
+
+    // See if the method is already available from a public class
+    Class cl = pMethod.getDeclaringClass ();
+    if (Modifier.isPublic (cl.getModifiers ())) {
+      return pMethod;
+    }
+
+    // Otherwise, try to find a public class that declares the method
+    Method ret = getPublicMethod (cl, pMethod);
+    if (ret != null) {
+      return ret;
+    }
+    else {
+      return pMethod;
+    }
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * If the given class is public and has a Method that declares the
+   * same name and arguments as the given method, then that method is
+   * returned.  Otherwise the superclass and interfaces are searched
+   * recursively.
+   **/
+  static Method getPublicMethod (Class pClass,
+				 Method pMethod)
+  {
+    // See if this is a public class declaring the method
+    if (Modifier.isPublic (pClass.getModifiers ())) {
+      try {
+        Method m;
+        try {
+	  m = pClass.getDeclaredMethod (pMethod.getName (),
+					     pMethod.getParameterTypes ());
+        } catch (java.security.AccessControlException ex) {
+	  // kludge to accommodate J2EE RI's default settings
+	  // TODO: see if we can simply replace
+          //       getDeclaredMethod() with getMethod() ...?
+          m = pClass.getMethod(pMethod.getName (),
+                                             pMethod.getParameterTypes ());
+        }
+	if (Modifier.isPublic (m.getModifiers ())) {
+	  return m;
+	}
+      }
+      catch (NoSuchMethodException exc) {}
+    }
+
+    // Search the interfaces
+    {
+      Class [] interfaces = pClass.getInterfaces ();
+      if (interfaces != null) {
+	for (int i = 0; i < interfaces.length; i++) {
+	  Method m = getPublicMethod (interfaces [i], pMethod);
+	  if (m != null) {
+	    return m;
+	  }
+	}
+      }
+    }
+
+    // Search the superclass
+    {
+      Class superclass = pClass.getSuperclass ();
+      if (superclass != null) {
+	Method m = getPublicMethod (superclass, pMethod);
+	if (m != null) {
+	  return m;
+	}
+      }
+    }
+
+    return null;
+  }
+
+  //-------------------------------------
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/BeanInfoProperty.java b/standard/src/org/apache/taglibs/standard/lang/jstl/BeanInfoProperty.java
new file mode 100644
index 0000000..023b2a7
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/BeanInfoProperty.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl;
+
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.Method;
+
+/**
+ *
+ * <p>This contains the information for one property in a BeanInfo -
+ * PropertyDescriptor, read method, and write method.  This class is
+ * necessary because the read/write methods in the PropertyDescriptor
+ * may not be accessible if the bean given to the introspector is not
+ * a public class.  In this case, a publicly accessible version of the
+ * method must be found by searching for a public superclass/interface
+ * that declares the method (this searching is done by the
+ * BeanInfoManager).
+ * 
+ * @author Nathan Abramson - Art Technology Group
+ * @version $Change: 181181 $$DateTime: 2001/06/26 09:55:09 $$Author: pierred $
+ **/
+
+public class BeanInfoProperty
+{
+  //-------------------------------------
+  // Properties
+  //-------------------------------------
+  // property readMethod
+
+  Method mReadMethod;
+  public Method getReadMethod ()
+  { return mReadMethod; }
+
+  //-------------------------------------
+  // property writeMethod
+
+  Method mWriteMethod;
+  public Method getWriteMethod ()
+  { return mWriteMethod; }
+
+  //-------------------------------------
+  // property propertyDescriptor
+
+  PropertyDescriptor mPropertyDescriptor;
+  public PropertyDescriptor getPropertyDescriptor ()
+  { return mPropertyDescriptor; }
+
+  //-------------------------------------
+  /**
+   *
+   * Constructor
+   **/
+  public BeanInfoProperty (Method pReadMethod,
+			   Method pWriteMethod,
+			   PropertyDescriptor pPropertyDescriptor)
+  {
+    mReadMethod = pReadMethod;
+    mWriteMethod = pWriteMethod;
+    mPropertyDescriptor = pPropertyDescriptor;
+  }
+
+  //-------------------------------------
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/BinaryOperator.java b/standard/src/org/apache/taglibs/standard/lang/jstl/BinaryOperator.java
new file mode 100644
index 0000000..9ef748e
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/BinaryOperator.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl;
+
+/**
+ *
+ * <p>This is the superclass for all binary operators
+ * 
+ * @author Nathan Abramson - Art Technology Group
+ * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: pierred $
+ **/
+
+public abstract class BinaryOperator
+{
+  //-------------------------------------
+  /**
+   *
+   * Constructor
+   **/
+  public BinaryOperator ()
+  {
+  }
+
+  //-------------------------------------
+  // Expression methods
+  //-------------------------------------
+  /**
+   *
+   * Returns the symbol representing the operator
+   **/
+  public abstract String getOperatorSymbol ();
+
+  //-------------------------------------
+  /**
+   *
+   * Applies the operator to the given pair of values
+   **/
+  public abstract Object apply (Object pLeft,
+				Object pRight,
+				Object pContext,
+				Logger pLogger)
+    throws ELException;
+
+  //-------------------------------------
+  /**
+   *
+   * Returns true if evaluation is necessary given the specified Left
+   * value.  The And/OrOperators make use of this
+   **/
+  public boolean shouldEvaluate (Object pLeft)
+  {
+    return true;
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Returns true if the operator expects its arguments to be coerced
+   * to Booleans.  The And/Or operators set this to true.
+   **/
+  public boolean shouldCoerceToBoolean ()
+  {
+    return false;
+  }
+
+  //-------------------------------------
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/BinaryOperatorExpression.java b/standard/src/org/apache/taglibs/standard/lang/jstl/BinaryOperatorExpression.java
new file mode 100644
index 0000000..aa5f7ad
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/BinaryOperatorExpression.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ *
+ * <p>An expression representing a binary operator on a value
+ * 
+ * @author Nathan Abramson - Art Technology Group
+ * @author Shawn Bayern
+ * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: pierred $
+ **/
+
+public class BinaryOperatorExpression
+  extends Expression
+{
+  //-------------------------------------
+  // Properties
+  //-------------------------------------
+  // property expression
+
+  Expression mExpression;
+  public Expression getExpression ()
+  { return mExpression; }
+  public void setExpression (Expression pExpression)
+  { mExpression = pExpression; }
+
+  //-------------------------------------
+  // property operators
+
+  List mOperators;
+  public List getOperators ()
+  { return mOperators; }
+  public void setOperators (List pOperators)
+  { mOperators = pOperators; }
+
+  //-------------------------------------
+  // property expressions
+
+  List mExpressions;
+  public List getExpressions ()
+  { return mExpressions; }
+  public void setExpressions (List pExpressions)
+  { mExpressions = pExpressions; }
+
+  //-------------------------------------
+  /**
+   *
+   * Constructor
+   **/
+  public BinaryOperatorExpression (Expression pExpression,
+				   List pOperators,
+				   List pExpressions)
+  {
+    mExpression = pExpression;
+    mOperators = pOperators;
+    mExpressions = pExpressions;
+  }
+
+  //-------------------------------------
+  // Expression methods
+  //-------------------------------------
+  /**
+   *
+   * Returns the expression in the expression language syntax
+   **/
+  public String getExpressionString ()
+  {
+    StringBuffer buf = new StringBuffer ();
+    buf.append ("(");
+    buf.append (mExpression.getExpressionString ());
+    for (int i = 0; i < mOperators.size (); i++) {
+      BinaryOperator operator = (BinaryOperator) mOperators.get (i);
+      Expression expression = (Expression) mExpressions.get (i);
+      buf.append (" ");
+      buf.append (operator.getOperatorSymbol ());
+      buf.append (" ");
+      buf.append (expression.getExpressionString ());
+    }
+    buf.append (")");
+
+    return buf.toString ();
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Evaluates to the literal value
+   **/
+  public Object evaluate (Object pContext,
+			  VariableResolver pResolver,
+			  Map functions,
+			  String defaultPrefix,
+			  Logger pLogger)
+    throws ELException
+  {
+    Object value = mExpression.evaluate (pContext, pResolver, functions,
+					 defaultPrefix, pLogger);
+    for (int i = 0; i < mOperators.size (); i++) {
+      BinaryOperator operator = (BinaryOperator) mOperators.get (i);
+
+      // For the And/Or operators, we need to coerce to a boolean
+      // before testing if we shouldEvaluate
+      if (operator.shouldCoerceToBoolean ()) {
+	value = Coercions.coerceToBoolean (value, pLogger);
+      }
+
+      if (operator.shouldEvaluate (value)) {
+	Expression expression = (Expression) mExpressions.get (i);
+	Object nextValue = expression.evaluate (pContext, pResolver,
+						functions, defaultPrefix,
+						pLogger);
+
+	value = operator.apply (value, nextValue, pContext, pLogger);
+      }
+    }
+    return value;
+  }
+
+  //-------------------------------------
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/BooleanLiteral.java b/standard/src/org/apache/taglibs/standard/lang/jstl/BooleanLiteral.java
new file mode 100644
index 0000000..1a72bc6
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/BooleanLiteral.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl;
+
+/**
+ *
+ * <p>An expression representing a boolean literal value
+ * 
+ * @author Nathan Abramson - Art Technology Group
+ * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: pierred $
+ **/
+
+public class BooleanLiteral
+  extends Literal
+{
+  //-------------------------------------
+  // Member variables
+  //-------------------------------------
+
+  public static final BooleanLiteral TRUE = new BooleanLiteral ("true");
+  public static final BooleanLiteral FALSE = new BooleanLiteral ("false");
+
+  //-------------------------------------
+  /**
+   *
+   * Constructor
+   **/
+  public BooleanLiteral (String pToken)
+  {
+    super (getValueFromToken (pToken));
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Parses the given token into the literal value
+   **/
+  static Object getValueFromToken (String pToken)
+  {
+    return
+      ("true".equals (pToken)) ?
+      Boolean.TRUE :
+      Boolean.FALSE;
+  }
+
+  //-------------------------------------
+  // Expression methods
+  //-------------------------------------
+  /**
+   *
+   * Returns the expression in the expression language syntax
+   **/
+  public String getExpressionString ()
+  {
+    return (getValue () == Boolean.TRUE) ? "true" : "false";
+  }
+
+  //-------------------------------------
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/Coercions.java b/standard/src/org/apache/taglibs/standard/lang/jstl/Coercions.java
new file mode 100644
index 0000000..1f5f5cd
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/Coercions.java
@@ -0,0 +1,1024 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl;
+
+import java.beans.PropertyEditor;
+import java.beans.PropertyEditorManager;
+
+/**
+ *
+ * <p>This class contains the logic for coercing data types before
+ * operators are applied to them.
+ *
+ * <p>The following is the list of rules applied for various type
+ * conversions.
+ *
+ * <ul><pre>
+ * Applying arithmetic operator
+ *   Binary operator - A {+,-,*} B
+ *     if A and B are null
+ *       return 0
+ *     if A or B is Float, Double, or String containing ".", "e", or "E"
+ *       coerce both A and B to Double
+ *       apply operator
+ *     otherwise
+ *       coerce both A and B to Long
+ *       apply operator
+ *     if operator results in exception (such as divide by 0), error
+ * 
+ *   Binary operator - A {/,div} B
+ *     if A and B are null
+ *       return 0
+ *     otherwise
+ *       coerce both A and B to Double
+ *       apply operator
+ *     if operator results in exception (such as divide by 0), error
+ * 
+ *   Binary operator - A {%,mod} B
+ *     if A and B are null
+ *       return 0
+ *     if A or B is Float, Double, or String containing ".", "e" or "E"
+ *       coerce both to Double
+ *       apply operator
+ *     otherwise
+ *       coerce both A and B to Long
+ *       apply operator
+ *     if operator results in exception (such as divide by 0), error
+ * 
+ *   Unary minus operator - -A
+ *     if A is null
+ *       return 0
+ *     if A is String
+ *       if A contains ".", "e", or "E"
+ *         coerce to Double, apply operator
+ *       otherwise
+ *         coerce to a Long and apply operator
+ *     if A is Byte,Short,Integer,Long,Float,Double
+ *       retain type, apply operator
+ *     if operator results in exception, error
+ *     otherwise
+ *       error
+ *
+ * Applying "empty" operator - empty A
+ *   if A is null
+ *     return true
+ *   if A is zero-length String
+ *     return true
+ *   if A is zero-length array
+ *     return true
+ *   if A is List and ((List) A).isEmpty()
+ *     return true
+ *   if A is Map and ((Map) A).isEmpty()
+ *     return true
+ *   otherwise
+ *     return false
+ * 
+ * Applying logical operators
+ *   Binary operator - A {and,or} B
+ *     coerce both A and B to Boolean, apply operator
+ *   NOTE - operator stops as soon as expression can be determined, i.e.,
+ *     A and B and C and D - if B is false, then only A and B is evaluated
+ *   Unary not operator - not A
+ *     coerce A to Boolean, apply operator
+ * 
+ * Applying relational operator
+ *   A {<,>,<=,>=,lt,gt,lte,gte} B
+ *     if A==B
+ *       if operator is >= or <=
+ *         return true
+ *       otherwise
+ *         return false
+ *     if A or B is null
+ *       return false
+ *     if A or B is Float or Double
+ *       coerce both A and B to Double
+ *       apply operator
+ *     if A or B is Byte,Short,Character,Integer,Long
+ *       coerce both A and B to Long
+ *       apply operator
+ *     if A or B is String
+ *       coerce both A and B to String, compare lexically
+ *     if A is Comparable
+ *       if A.compareTo (B) throws exception
+ *         error
+ *       otherwise
+ *         use result of A.compareTo(B)
+ *     if B is Comparable
+ *       if B.compareTo (A) throws exception
+ *         error
+ *       otherwise
+ *         use result of B.compareTo(A)
+ *     otherwise
+ *       error
+ * 
+ * Applying equality operator
+ *   A {==,!=} B
+ *     if A==B
+ *       apply operator
+ *     if A or B is null
+ *       return false for ==, true for !=
+ *     if A or B is Float or Double
+ *       coerce both A and B to Double
+ *       apply operator
+ *     if A or B is Byte,Short,Character,Integer,Long
+ *       coerce both A and B to Long
+ *       apply operator
+ *     if A or B is Boolean
+ *       coerce both A and B to Boolean
+ *       apply operator
+ *     if A or B is String
+ *       coerce both A and B to String, compare lexically
+ *     otherwise
+ *       if an error occurs while calling A.equals(B)
+ *         error
+ *       apply operator to result of A.equals(B)
+ * 
+ * coercions
+ * 
+ *   coerce A to String
+ *     A is String
+ *       return A
+ *     A is null
+ *       return ""
+ *     A.toString throws exception
+ *       error
+ *     otherwise
+ *       return A.toString
+ * 
+ *   coerce A to primitive Number type N
+ *     A is null or ""
+ *       return 0
+ *     A is Character
+ *       convert to short, apply following rules
+ *     A is Boolean
+ *       error
+ *     A is Number type N
+ *       return A
+ *     A is Number with less precision than N
+ *       coerce quietly
+ *     A is Number with greater precision than N
+ *       coerce quietly
+ *     A is String
+ *       new N.valueOf(A) throws exception
+ *         error
+ *       return N.valueOf(A)
+ *     otherwise
+ *       error
+ * 
+ *   coerce A to Character should be
+ *     A is null or ""
+ *       return (char) 0
+ *     A is Character
+ *       return A
+ *     A is Boolean
+ *       error
+ *     A is Number with less precision than short
+ *       coerce quietly - return (char) A
+ *     A is Number with greater precision than short
+ *       coerce quietly - return (char) A
+ *     A is String
+ *       return A.charAt (0)
+ *     otherwise
+ *       error
+ * 
+ *   coerce A to Boolean
+ *     A is null or ""
+ *       return false
+ *     A is Boolean
+ *       return A
+ *     A is String
+ *       Boolean.valueOf(A) throws exception
+ *         error
+ *       return Boolean.valueOf(A)
+ *     otherwise
+ *       error
+ * 
+ *   coerce A to any other type T
+ *     A is null
+ *       return null
+ *     A is assignable to T
+ *       coerce quietly
+ *     A is String
+ *       T has no PropertyEditor
+ *         if A is "", return null
+ *         otherwise error
+ *       T's PropertyEditor throws exception
+ *         if A is "", return null
+ *         otherwise error
+ *       otherwise
+ *         apply T's PropertyEditor
+ *     otherwise
+ *       error
+ * </pre></ul>
+ *
+ * @author Nathan Abramson - Art Technology Group
+ * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: pierred $
+ **/
+
+public class Coercions
+{
+  //-------------------------------------
+  /**
+   *
+   * Coerces the given value to the specified class.
+   **/
+  public static Object coerce (Object pValue,
+			       Class pClass,
+			       Logger pLogger)
+    throws ELException
+  {
+    if (pClass == String.class) {
+      return coerceToString (pValue, pLogger);
+    }
+    else if (isPrimitiveNumberClass (pClass)) {
+      return coerceToPrimitiveNumber (pValue, pClass, pLogger);
+    }
+    else if (pClass == Character.class ||
+	     pClass == Character.TYPE) {
+      return coerceToCharacter (pValue, pLogger);
+    }
+    else if (pClass == Boolean.class ||
+	     pClass == Boolean.TYPE) {
+      return coerceToBoolean (pValue, pLogger);
+    }
+    else {
+      return coerceToObject (pValue, pClass, pLogger);
+    }
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Returns true if the given class is Byte, Short, Integer, Long,
+   * Float, Double
+   **/
+  static boolean isPrimitiveNumberClass (Class pClass)
+  {
+    return
+      pClass == Byte.class ||
+      pClass == Byte.TYPE ||
+      pClass == Short.class ||
+      pClass == Short.TYPE ||
+      pClass == Integer.class ||
+      pClass == Integer.TYPE ||
+      pClass == Long.class ||
+      pClass == Long.TYPE ||
+      pClass == Float.class ||
+      pClass == Float.TYPE ||
+      pClass == Double.class ||
+      pClass == Double.TYPE;
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Coerces the specified value to a String
+   **/
+  public static String coerceToString (Object pValue,
+				       Logger pLogger)
+    throws ELException
+  {
+    if (pValue == null) {
+      return "";
+    }
+    else if (pValue instanceof String) {
+      return (String) pValue;
+    }
+    else {
+      try {
+	return pValue.toString ();
+      }
+      catch (Exception exc) {
+	if (pLogger.isLoggingError ()) {
+	  pLogger.logError (Constants.TOSTRING_EXCEPTION,
+			    exc,
+			    pValue.getClass ().getName ());
+	}
+	return "";
+      }
+    }
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Coerces a value to the given primitive number class
+   **/
+  public static Number coerceToPrimitiveNumber (Object pValue,
+						Class pClass,
+						Logger pLogger)
+    throws ELException
+  {
+    if (pValue == null ||
+	"".equals (pValue)) {
+      return coerceToPrimitiveNumber (0, pClass);
+    }
+    else if (pValue instanceof Character) {
+      char val = ((Character) pValue).charValue ();
+      return coerceToPrimitiveNumber ((short) val, pClass);
+    }
+    else if (pValue instanceof Boolean) {
+      if (pLogger.isLoggingError ()) {
+	pLogger.logError (Constants.BOOLEAN_TO_NUMBER,
+			  pValue,
+			  pClass.getName ());
+      }
+      return coerceToPrimitiveNumber (0, pClass);
+    }
+    else if (pValue.getClass () == pClass) {
+      return (Number) pValue;
+    }
+    else if (pValue instanceof Number) {
+      return coerceToPrimitiveNumber ((Number) pValue, pClass);
+    }
+    else if (pValue instanceof String) {
+      try {
+	return coerceToPrimitiveNumber ((String) pValue, pClass);
+      }
+      catch (Exception exc) {
+	if (pLogger.isLoggingError ()) {
+	  pLogger.logError
+	    (Constants.STRING_TO_NUMBER_EXCEPTION,
+	     (String) pValue,
+	     pClass.getName ());
+	}
+	return coerceToPrimitiveNumber (0, pClass);
+      }
+    }
+    else {
+      if (pLogger.isLoggingError ()) {
+	pLogger.logError
+	  (Constants.COERCE_TO_NUMBER,
+	   pValue.getClass ().getName (),
+	   pClass.getName ());
+      }
+      return coerceToPrimitiveNumber (0, pClass);
+    }
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Coerces a value to an Integer, returning null if the coercion
+   * isn't possible.
+   **/
+  public static Integer coerceToInteger (Object pValue,
+					 Logger pLogger)
+    throws ELException
+  {
+    if (pValue == null) {
+      return null;
+    }
+    else if (pValue instanceof Character) {
+      return PrimitiveObjects.getInteger 
+	((int) (((Character) pValue).charValue ()));
+    }
+    else if (pValue instanceof Boolean) {
+      if (pLogger.isLoggingWarning ()) {
+	pLogger.logWarning (Constants.BOOLEAN_TO_NUMBER,
+			    pValue,
+			    Integer.class.getName ());
+      }
+      return PrimitiveObjects.getInteger
+	(((Boolean) pValue).booleanValue () ? 1 : 0);
+    }
+    else if (pValue instanceof Integer) {
+      return (Integer) pValue;
+    }
+    else if (pValue instanceof Number) {
+      return PrimitiveObjects.getInteger (((Number) pValue).intValue ());
+    }
+    else if (pValue instanceof String) {
+      try {
+	return Integer.valueOf ((String) pValue);
+      }
+      catch (Exception exc) {
+	if (pLogger.isLoggingWarning ()) {
+	  pLogger.logWarning
+	    (Constants.STRING_TO_NUMBER_EXCEPTION,
+	     (String) pValue,
+	     Integer.class.getName ());
+	}
+	return null;
+      }
+    }
+    else {
+      if (pLogger.isLoggingWarning ()) {
+	pLogger.logWarning
+	  (Constants.COERCE_TO_NUMBER,
+	   pValue.getClass ().getName (),
+	   Integer.class.getName ());
+      }
+      return null;
+    }
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Coerces a long to the given primitive number class
+   **/
+  static Number coerceToPrimitiveNumber (long pValue,
+					 Class pClass)
+    throws ELException
+  {
+    if (pClass == Byte.class || pClass == Byte.TYPE) {
+      return PrimitiveObjects.getByte ((byte) pValue);
+    }
+    else if (pClass == Short.class || pClass == Short.TYPE) {
+      return PrimitiveObjects.getShort ((short) pValue);
+    }
+    else if (pClass == Integer.class || pClass == Integer.TYPE) {
+      return PrimitiveObjects.getInteger ((int) pValue);
+    }
+    else if (pClass == Long.class || pClass == Long.TYPE) {
+      return PrimitiveObjects.getLong ((long) pValue);
+    }
+    else if (pClass == Float.class || pClass == Float.TYPE) {
+      return PrimitiveObjects.getFloat ((float) pValue);
+    }
+    else if (pClass == Double.class || pClass == Double.TYPE) {
+      return PrimitiveObjects.getDouble ((double) pValue);
+    }
+    else {
+      return PrimitiveObjects.getInteger (0);
+    }
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Coerces a double to the given primitive number class
+   **/
+  static Number coerceToPrimitiveNumber (double pValue,
+					 Class pClass)
+    throws ELException
+  {
+    if (pClass == Byte.class || pClass == Byte.TYPE) {
+      return PrimitiveObjects.getByte ((byte) pValue);
+    }
+    else if (pClass == Short.class || pClass == Short.TYPE) {
+      return PrimitiveObjects.getShort ((short) pValue);
+    }
+    else if (pClass == Integer.class || pClass == Integer.TYPE) {
+      return PrimitiveObjects.getInteger ((int) pValue);
+    }
+    else if (pClass == Long.class || pClass == Long.TYPE) {
+      return PrimitiveObjects.getLong ((long) pValue);
+    }
+    else if (pClass == Float.class || pClass == Float.TYPE) {
+      return PrimitiveObjects.getFloat ((float) pValue);
+    }
+    else if (pClass == Double.class || pClass == Double.TYPE) {
+      return PrimitiveObjects.getDouble ((double) pValue);
+    }
+    else {
+      return PrimitiveObjects.getInteger (0);
+    }
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Coerces a Number to the given primitive number class
+   **/
+  static Number coerceToPrimitiveNumber (Number pValue,
+					 Class pClass)
+    throws ELException
+  {
+    if (pClass == Byte.class || pClass == Byte.TYPE) {
+      return PrimitiveObjects.getByte (pValue.byteValue ());
+    }
+    else if (pClass == Short.class || pClass == Short.TYPE) {
+      return PrimitiveObjects.getShort (pValue.shortValue ());
+    }
+    else if (pClass == Integer.class || pClass == Integer.TYPE) {
+      return PrimitiveObjects.getInteger (pValue.intValue ());
+    }
+    else if (pClass == Long.class || pClass == Long.TYPE) {
+      return PrimitiveObjects.getLong (pValue.longValue ());
+    }
+    else if (pClass == Float.class || pClass == Float.TYPE) {
+      return PrimitiveObjects.getFloat (pValue.floatValue ());
+    }
+    else if (pClass == Double.class || pClass == Double.TYPE) {
+      return PrimitiveObjects.getDouble (pValue.doubleValue ());
+    }
+    else {
+      return PrimitiveObjects.getInteger (0);
+    }
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Coerces a String to the given primitive number class
+   **/
+  static Number coerceToPrimitiveNumber (String pValue,
+					 Class pClass)
+    throws ELException
+  {
+    if (pClass == Byte.class || pClass == Byte.TYPE) {
+      return Byte.valueOf (pValue);
+    }
+    else if (pClass == Short.class || pClass == Short.TYPE) {
+      return Short.valueOf (pValue);
+    }
+    else if (pClass == Integer.class || pClass == Integer.TYPE) {
+      return Integer.valueOf (pValue);
+    }
+    else if (pClass == Long.class || pClass == Long.TYPE) {
+      return Long.valueOf (pValue);
+    }
+    else if (pClass == Float.class || pClass == Float.TYPE) {
+      return Float.valueOf (pValue);
+    }
+    else if (pClass == Double.class || pClass == Double.TYPE) {
+      return Double.valueOf (pValue);
+    }
+    else {
+      return PrimitiveObjects.getInteger (0);
+    }
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Coerces a value to a Character
+   **/
+  public static Character coerceToCharacter (Object pValue,
+					     Logger pLogger)
+    throws ELException
+  {
+    if (pValue == null ||
+	"".equals (pValue)) {
+      return PrimitiveObjects.getCharacter ((char) 0);
+    }
+    else if (pValue instanceof Character) {
+      return (Character) pValue;
+    }
+    else if (pValue instanceof Boolean) {
+      if (pLogger.isLoggingError ()) {
+	pLogger.logError (Constants.BOOLEAN_TO_CHARACTER, pValue);
+      }
+      return PrimitiveObjects.getCharacter ((char) 0);
+    }
+    else if (pValue instanceof Number) {
+      return PrimitiveObjects.getCharacter 
+	((char) ((Number) pValue).shortValue ());
+    }
+    else if (pValue instanceof String) {
+      String str = (String) pValue;
+      return PrimitiveObjects.getCharacter (str.charAt (0));
+    }
+    else {
+      if (pLogger.isLoggingError ()) {
+	pLogger.logError
+	  (Constants.COERCE_TO_CHARACTER,
+	   pValue.getClass ().getName ());
+      }
+      return PrimitiveObjects.getCharacter ((char) 0);
+    }
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Coerces a value to a Boolean
+   **/
+  public static Boolean coerceToBoolean (Object pValue,
+					 Logger pLogger)
+    throws ELException
+  {
+    if (pValue == null ||
+	"".equals (pValue)) {
+      return Boolean.FALSE;
+    }
+    else if (pValue instanceof Boolean) {
+      return (Boolean) pValue;
+    }
+    else if (pValue instanceof String) {
+      String str = (String) pValue;
+      try {
+	return Boolean.valueOf (str);
+      }
+      catch (Exception exc) {
+	if (pLogger.isLoggingError ()) {
+	  pLogger.logError
+	    (Constants.STRING_TO_BOOLEAN,
+	     exc,
+	     (String) pValue);
+	}
+	return Boolean.FALSE;
+      }
+    }
+    else {
+      if (pLogger.isLoggingError ()) {
+	pLogger.logError
+	  (Constants.COERCE_TO_BOOLEAN,
+	   pValue.getClass ().getName ());
+      }
+      return Boolean.TRUE;
+    }
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Coerces a value to the specified Class that is not covered by any
+   * of the above cases
+   **/
+  public static Object coerceToObject (Object pValue,
+				       Class pClass,
+				       Logger pLogger)
+    throws ELException
+  {
+    if (pValue == null) {
+      return null;
+    }
+    else if (pClass.isAssignableFrom (pValue.getClass ())) {
+      return pValue;
+    }
+    else if (pValue instanceof String) {
+      String str = (String) pValue;
+      PropertyEditor pe = PropertyEditorManager.findEditor (pClass);
+      if (pe == null) {
+	if ("".equals (str)) {
+	  return null;
+	}
+	else {
+	  if (pLogger.isLoggingError ()) {
+	    pLogger.logError
+	      (Constants.NO_PROPERTY_EDITOR,
+	       str,
+	       pClass.getName ());
+	  }
+	  return null;
+	}
+      }
+      try {
+	pe.setAsText (str);
+	return pe.getValue ();
+      }
+      catch (IllegalArgumentException exc) {
+	if ("".equals (str)) {
+	  return null;
+	}
+	else {
+	  if (pLogger.isLoggingError ()) {
+	    pLogger.logError
+	      (Constants.PROPERTY_EDITOR_ERROR,
+	       exc,
+	       pValue,
+	       pClass.getName ());
+	  }
+	  return null;
+	}
+      }
+    }
+    else {
+      if (pLogger.isLoggingError ()) {
+	pLogger.logError
+	  (Constants.COERCE_TO_OBJECT,
+	   pValue.getClass ().getName (),
+	   pClass.getName ());
+      }
+      return null;
+    }
+  }
+
+  //-------------------------------------
+  // Applying operators
+  //-------------------------------------
+  /**
+   *
+   * Performs all of the necessary type conversions, then calls on the
+   * appropriate operator.
+   **/
+  public static Object applyArithmeticOperator 
+    (Object pLeft,
+     Object pRight,
+     ArithmeticOperator pOperator,
+     Logger pLogger)
+    throws ELException
+  {
+    if (pLeft == null &&
+	pRight == null) {
+      if (pLogger.isLoggingWarning ()) {
+	pLogger.logWarning
+	  (Constants.ARITH_OP_NULL,
+	   pOperator.getOperatorSymbol ());
+      }
+      return PrimitiveObjects.getInteger (0);
+    }
+
+    else if (isFloatingPointType (pLeft) ||
+	     isFloatingPointType (pRight) ||
+	     isFloatingPointString (pLeft) ||
+	     isFloatingPointString (pRight)) {
+      double left =
+	coerceToPrimitiveNumber (pLeft, Double.class, pLogger).
+	doubleValue ();
+      double right =
+	coerceToPrimitiveNumber (pRight, Double.class, pLogger).
+	doubleValue ();
+      return 
+	PrimitiveObjects.getDouble (pOperator.apply (left, right, pLogger));
+    }
+
+    else {
+      long left =
+	coerceToPrimitiveNumber (pLeft, Long.class, pLogger).
+	longValue ();
+      long right =
+	coerceToPrimitiveNumber (pRight, Long.class, pLogger).
+	longValue ();
+      return
+	PrimitiveObjects.getLong (pOperator.apply (left, right, pLogger));
+    }
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Performs all of the necessary type conversions, then calls on the
+   * appropriate operator.
+   **/
+  public static Object applyRelationalOperator 
+    (Object pLeft,
+     Object pRight,
+     RelationalOperator pOperator,
+     Logger pLogger)
+    throws ELException
+  {
+    if (isFloatingPointType (pLeft) ||
+	isFloatingPointType (pRight)) {
+      double left =
+	coerceToPrimitiveNumber (pLeft, Double.class, pLogger).
+	doubleValue ();
+      double right =
+	coerceToPrimitiveNumber (pRight, Double.class, pLogger).
+	doubleValue ();
+      return 
+	PrimitiveObjects.getBoolean (pOperator.apply (left, right, pLogger));
+    }
+
+    else if (isIntegerType (pLeft) ||
+	     isIntegerType (pRight)) {
+      long left =
+	coerceToPrimitiveNumber (pLeft, Long.class, pLogger).
+	longValue ();
+      long right =
+	coerceToPrimitiveNumber (pRight, Long.class, pLogger).
+	longValue ();
+      return
+	PrimitiveObjects.getBoolean (pOperator.apply (left, right, pLogger));
+    }
+
+    else if (pLeft instanceof String ||
+	     pRight instanceof String) {
+      String left = coerceToString (pLeft, pLogger);
+      String right = coerceToString (pRight, pLogger);
+      return
+	PrimitiveObjects.getBoolean (pOperator.apply (left, right, pLogger));
+    }
+
+    else if (pLeft instanceof Comparable) {
+      try {
+	int result = ((Comparable) pLeft).compareTo (pRight);
+	return
+	  PrimitiveObjects.getBoolean 
+	  (pOperator.apply (result, -result, pLogger));
+      }
+      catch (Exception exc) {
+	if (pLogger.isLoggingError ()) {
+	  pLogger.logError
+	    (Constants.COMPARABLE_ERROR,
+	     exc,
+	     pLeft.getClass ().getName (),
+	     (pRight == null) ? "null" : pRight.getClass ().getName (),
+	     pOperator.getOperatorSymbol ());
+	}
+	return Boolean.FALSE;
+      }
+    }
+
+    else if (pRight instanceof Comparable) {
+      try {
+	int result = ((Comparable) pRight).compareTo (pLeft);
+	return
+	  PrimitiveObjects.getBoolean 
+	  (pOperator.apply (-result, result, pLogger));
+      }
+      catch (Exception exc) {
+	if (pLogger.isLoggingError ()) {
+	  pLogger.logError
+	    (Constants.COMPARABLE_ERROR,
+	     exc,
+	     pRight.getClass ().getName (),
+	     (pLeft == null) ? "null" : pLeft.getClass ().getName (),
+	     pOperator.getOperatorSymbol ());
+	}
+	return Boolean.FALSE;
+      }
+    }
+
+    else {
+      if (pLogger.isLoggingError ()) {
+	pLogger.logError
+	  (Constants.ARITH_OP_BAD_TYPE,
+	   pOperator.getOperatorSymbol (),
+	   pLeft.getClass ().getName (),
+	   pRight.getClass ().getName ());
+      }
+      return Boolean.FALSE;
+    }
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Performs all of the necessary type conversions, then calls on the
+   * appropriate operator.
+   **/
+  public static Object applyEqualityOperator 
+    (Object pLeft,
+     Object pRight,
+     EqualityOperator pOperator,
+     Logger pLogger)
+    throws ELException
+  {
+    if (pLeft == pRight) {
+      return PrimitiveObjects.getBoolean (pOperator.apply (true, pLogger));
+    }
+
+    else if (pLeft == null ||
+	     pRight == null) {
+      return PrimitiveObjects.getBoolean (pOperator.apply (false, pLogger));
+    }
+
+    else if (isFloatingPointType (pLeft) ||
+	     isFloatingPointType (pRight)) {
+      double left =
+	coerceToPrimitiveNumber (pLeft, Double.class, pLogger).
+	doubleValue ();
+      double right =
+	coerceToPrimitiveNumber (pRight, Double.class, pLogger).
+	doubleValue ();
+      return 
+	PrimitiveObjects.getBoolean 
+	(pOperator.apply (left == right, pLogger));
+    }
+
+    else if (isIntegerType (pLeft) ||
+	     isIntegerType (pRight)) {
+      long left =
+	coerceToPrimitiveNumber (pLeft, Long.class, pLogger).
+	longValue ();
+      long right =
+	coerceToPrimitiveNumber (pRight, Long.class, pLogger).
+	longValue ();
+      return
+	PrimitiveObjects.getBoolean 
+	(pOperator.apply (left == right, pLogger));
+    }
+
+    else if (pLeft instanceof Boolean ||
+	     pRight instanceof Boolean) {
+      boolean left = coerceToBoolean (pLeft, pLogger).booleanValue ();
+      boolean right = coerceToBoolean (pRight, pLogger).booleanValue ();
+      return
+	PrimitiveObjects.getBoolean 
+	(pOperator.apply (left == right, pLogger));
+    }
+
+    else if (pLeft instanceof String ||
+	     pRight instanceof String) {
+      String left = coerceToString (pLeft, pLogger);
+      String right = coerceToString (pRight, pLogger);
+      return
+	PrimitiveObjects.getBoolean 
+	(pOperator.apply (left.equals (right), pLogger));
+    }
+
+    else {
+      try {
+      return
+	PrimitiveObjects.getBoolean
+	(pOperator.apply (pLeft.equals (pRight), pLogger));
+      }
+      catch (Exception exc) {
+	if (pLogger.isLoggingError ()) {
+	  pLogger.logError
+	    (Constants.ERROR_IN_EQUALS,
+	     exc,
+	     pLeft.getClass ().getName (),
+	     pRight.getClass ().getName (),
+	     pOperator.getOperatorSymbol ());
+	}
+	return Boolean.FALSE;
+      }
+    }
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Returns true if the given Object is of a floating point type
+   **/
+  public static boolean isFloatingPointType (Object pObject)
+  {
+    return 
+      pObject != null &&
+      isFloatingPointType (pObject.getClass ());
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Returns true if the given class is of a floating point type
+   **/
+  public static boolean isFloatingPointType (Class pClass)
+  {
+    return
+      pClass == Float.class ||
+      pClass == Float.TYPE ||
+      pClass == Double.class ||
+      pClass == Double.TYPE;
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Returns true if the given string might contain a floating point
+   * number - i.e., it contains ".", "e", or "E"
+   **/
+  public static boolean isFloatingPointString (Object pObject)
+  {
+    if (pObject instanceof String) {
+      String str = (String) pObject;
+      int len = str.length ();
+      for (int i = 0; i < len; i++) {
+	char ch = str.charAt (i);
+	if (ch == '.' ||
+	    ch == 'e' ||
+	    ch == 'E') {
+	  return true;
+	}
+      }
+      return false;
+    }
+    else {
+      return false;
+    }
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Returns true if the given Object is of an integer type
+   **/
+  public static boolean isIntegerType (Object pObject)
+  {
+    return 
+      pObject != null &&
+      isIntegerType (pObject.getClass ());
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Returns true if the given class is of an integer type
+   **/
+  public static boolean isIntegerType (Class pClass)
+  {
+    return
+      pClass == Byte.class ||
+      pClass == Byte.TYPE ||
+      pClass == Short.class ||
+      pClass == Short.TYPE ||
+      pClass == Character.class ||
+      pClass == Character.TYPE ||
+      pClass == Integer.class ||
+      pClass == Integer.TYPE ||
+      pClass == Long.class ||
+      pClass == Long.TYPE;
+  }
+
+  //-------------------------------------
+
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/ComplexValue.java b/standard/src/org/apache/taglibs/standard/lang/jstl/ComplexValue.java
new file mode 100644
index 0000000..26a57b6
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/ComplexValue.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ *
+ * <p>Represents a dynamic value, which consists of a prefix and an
+ * optional set of ValueSuffix elements.  A prefix is something like
+ * an identifier, and a suffix is something like a "property of" or
+ * "indexed element of" operator.
+ * 
+ * @author Nathan Abramson - Art Technology Group
+ * @author Shawn Bayern
+ * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: pierred $
+ **/
+
+public class ComplexValue
+  extends Expression
+{
+  //-------------------------------------
+  // Properties
+  //-------------------------------------
+  // property prefix
+
+  Expression mPrefix;
+  public Expression getPrefix ()
+  { return mPrefix; }
+  public void setPrefix (Expression pPrefix)
+  { mPrefix = pPrefix; }
+
+  //-------------------------------------
+  // property suffixes
+
+  List mSuffixes;
+  public List getSuffixes ()
+  { return mSuffixes; }
+  public void setSuffixes (List pSuffixes)
+  { mSuffixes = pSuffixes; }
+
+  //-------------------------------------
+  /**
+   *
+   * Constructor
+   **/
+  public ComplexValue (Expression pPrefix,
+		       List pSuffixes)
+  {
+    mPrefix = pPrefix;
+    mSuffixes = pSuffixes;
+  }
+
+  //-------------------------------------
+  // Expression methods
+  //-------------------------------------
+  /**
+   *
+   * Returns the expression in the expression language syntax
+   **/
+  public String getExpressionString ()
+  {
+    StringBuffer buf = new StringBuffer ();
+    buf.append (mPrefix.getExpressionString ());
+
+    for (int i = 0; mSuffixes != null && i < mSuffixes.size (); i++) {
+      ValueSuffix suffix = (ValueSuffix) mSuffixes.get (i);
+      buf.append (suffix.getExpressionString ());
+    }
+
+    return buf.toString ();
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Evaluates by evaluating the prefix, then applying the suffixes
+   **/
+  public Object evaluate (Object pContext,
+			  VariableResolver pResolver,
+			  Map functions,
+			  String defaultPrefix,
+			  Logger pLogger)
+    throws ELException
+  {
+    Object ret = mPrefix.evaluate (pContext, pResolver, functions,
+				   defaultPrefix, pLogger);
+
+    // Apply the suffixes
+    for (int i = 0; mSuffixes != null && i < mSuffixes.size (); i++) {
+      ValueSuffix suffix = (ValueSuffix) mSuffixes.get (i);
+      ret = suffix.evaluate (ret, pContext, pResolver, functions,
+			     defaultPrefix, pLogger);
+    }
+
+    return ret;
+  }
+
+  //-------------------------------------
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/Constants.java b/standard/src/org/apache/taglibs/standard/lang/jstl/Constants.java
new file mode 100644
index 0000000..60a6b61
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/Constants.java
@@ -0,0 +1,203 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl;
+
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+/**
+ *
+ * <p>This contains all of the non-public constants, including
+ * messsage strings read from the resource file.
+ *
+ * @author Nathan Abramson - Art Technology Group
+ * @author Shawn Bayern
+ *
+ * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: pierred $
+ **/
+
+public class Constants
+{
+  //-------------------------------------
+  // Resources
+
+  static ResourceBundle sResources =
+  ResourceBundle.getBundle ("org.apache.taglibs.standard.lang.jstl.Resources");
+
+  //-------------------------------------
+  // Messages from the resource bundle
+  //-------------------------------------
+
+  public static final String EXCEPTION_GETTING_BEANINFO =
+    getStringResource ("EXCEPTION_GETTING_BEANINFO");
+
+  public static final String NULL_EXPRESSION_STRING =
+    getStringResource ("NULL_EXPRESSION_STRING");
+
+  public static final String PARSE_EXCEPTION =
+    getStringResource ("PARSE_EXCEPTION");
+
+  public static final String CANT_GET_PROPERTY_OF_NULL =
+    getStringResource ("CANT_GET_PROPERTY_OF_NULL");
+
+  public static final String NO_SUCH_PROPERTY =
+    getStringResource ("NO_SUCH_PROPERTY");
+
+  public static final String NO_GETTER_METHOD =
+    getStringResource ("NO_GETTER_METHOD");
+
+  public static final String ERROR_GETTING_PROPERTY =
+    getStringResource ("ERROR_GETTING_PROPERTY");
+
+  public static final String CANT_GET_INDEXED_VALUE_OF_NULL =
+    getStringResource ("CANT_GET_INDEXED_VALUE_OF_NULL");
+
+  public static final String CANT_GET_NULL_INDEX =
+    getStringResource ("CANT_GET_NULL_INDEX");
+
+  public static final String NULL_INDEX =
+    getStringResource ("NULL_INDEX");
+
+  public static final String BAD_INDEX_VALUE =
+    getStringResource ("BAD_INDEX_VALUE");
+
+  public static final String EXCEPTION_ACCESSING_LIST =
+    getStringResource ("EXCEPTION_ACCESSING_LIST");
+
+  public static final String EXCEPTION_ACCESSING_ARRAY =
+    getStringResource ("EXCEPTION_ACCESSING_ARRAY");
+
+  public static final String CANT_FIND_INDEX =
+    getStringResource ("CANT_FIND_INDEX");
+
+  public static final String TOSTRING_EXCEPTION =
+    getStringResource ("TOSTRING_EXCEPTION");
+
+  public static final String BOOLEAN_TO_NUMBER =
+    getStringResource ("BOOLEAN_TO_NUMBER");
+
+  public static final String STRING_TO_NUMBER_EXCEPTION =
+    getStringResource ("STRING_TO_NUMBER_EXCEPTION");
+
+  public static final String COERCE_TO_NUMBER =
+    getStringResource ("COERCE_TO_NUMBER");
+
+  public static final String BOOLEAN_TO_CHARACTER =
+    getStringResource ("BOOLEAN_TO_CHARACTER");
+
+  public static final String EMPTY_STRING_TO_CHARACTER =
+    getStringResource ("EMPTY_STRING_TO_CHARACTER");
+
+  public static final String COERCE_TO_CHARACTER =
+    getStringResource ("COERCE_TO_CHARACTER");
+
+  public static final String NULL_TO_BOOLEAN =
+    getStringResource ("NULL_TO_BOOLEAN");
+
+  public static final String STRING_TO_BOOLEAN =
+    getStringResource ("STRING_TO_BOOLEAN");
+
+  public static final String COERCE_TO_BOOLEAN =
+    getStringResource ("COERCE_TO_BOOLEAN");
+
+  public static final String COERCE_TO_OBJECT =
+    getStringResource ("COERCE_TO_OBJECT");
+
+  public static final String NO_PROPERTY_EDITOR =
+    getStringResource ("NO_PROPERTY_EDITOR");
+
+  public static final String PROPERTY_EDITOR_ERROR =
+    getStringResource ("PROPERTY_EDITOR_ERROR");
+
+  public static final String ARITH_OP_NULL =
+    getStringResource ("ARITH_OP_NULL");
+
+  public static final String ARITH_OP_BAD_TYPE =
+    getStringResource ("ARITH_OP_BAD_TYPE");
+
+  public static final String ARITH_ERROR =
+    getStringResource ("ARITH_ERROR");
+
+  public static final String ERROR_IN_EQUALS =
+    getStringResource ("ERROR_IN_EQUALS");
+
+  public static final String UNARY_OP_BAD_TYPE =
+    getStringResource ("UNARY_OP_BAD_TYPE");
+
+  public static final String NAMED_VALUE_NOT_FOUND =
+    getStringResource ("NAMED_VALUE_NOT_FOUND");
+
+  public static final String CANT_GET_INDEXED_PROPERTY =
+    getStringResource ("CANT_GET_INDEXED_PROPERTY");
+
+  public static final String COMPARABLE_ERROR =
+    getStringResource ("COMPARABLE_ERROR");
+
+  public static final String BAD_IMPLICIT_OBJECT =
+    getStringResource ("BAD_IMPLICIT_OBJECT");
+
+  public static final String ATTRIBUTE_EVALUATION_EXCEPTION =
+    getStringResource ("ATTRIBUTE_EVALUATION_EXCEPTION");
+
+  public static final String ATTRIBUTE_PARSE_EXCEPTION =
+    getStringResource ("ATTRIBUTE_PARSE_EXCEPTION");
+
+  public static final String UNKNOWN_FUNCTION =
+    getStringResource ("UNKNOWN_FUNCTION");
+
+  public static final String INAPPROPRIATE_FUNCTION_ARG_COUNT =
+    getStringResource ("INAPPROPRIATE_FUNCTION_ARG_COUNT");
+
+  public static final String FUNCTION_INVOCATION_ERROR =
+    getStringResource ("FUNCTION_INVOCATION_ERROR");
+
+
+  //-------------------------------------
+  // Getting resources
+  //-------------------------------------
+  /**
+   *
+   * 
+   **/
+  public static String getStringResource (String pResourceName)
+    throws MissingResourceException
+  {
+    try {
+      String ret = sResources.getString (pResourceName);
+      if (ret == null) {
+	String str = "ERROR: Unable to load resource " + pResourceName;
+	System.err.println (str);
+	throw new MissingResourceException 
+	  (str, 
+	   "org.apache.taglibs.standard.lang.jstl.Constants",
+	   pResourceName);
+      }
+      else {
+	return ret;
+      }
+    }
+    catch (MissingResourceException exc) {
+      System.err.println ("ERROR: Unable to load resource " +
+			  pResourceName +
+			  ": " +
+			  exc);
+      throw exc;
+    }
+  }
+
+  //-------------------------------------
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/DivideOperator.java b/standard/src/org/apache/taglibs/standard/lang/jstl/DivideOperator.java
new file mode 100644
index 0000000..882c264
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/DivideOperator.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl;
+
+/**
+ *
+ * <p>The implementation of the divide operator
+ * 
+ * @author Nathan Abramson - Art Technology Group
+ * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: pierred $
+ **/
+
+public class DivideOperator
+  extends BinaryOperator
+{
+  //-------------------------------------
+  // Singleton
+  //-------------------------------------
+
+  public static final DivideOperator SINGLETON =
+    new DivideOperator ();
+
+  //-------------------------------------
+  /**
+   *
+   * Constructor
+   **/
+  public DivideOperator ()
+  {
+  }
+
+  //-------------------------------------
+  // Expression methods
+  //-------------------------------------
+  /**
+   *
+   * Returns the symbol representing the operator
+   **/
+  public String getOperatorSymbol ()
+  {
+    return "/";
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Applies the operator to the given value
+   **/
+  public Object apply (Object pLeft,
+		       Object pRight,
+		       Object pContext,
+		       Logger pLogger)
+    throws ELException
+  {
+    if (pLeft == null &&
+	pRight == null) {
+      if (pLogger.isLoggingWarning ()) {
+	pLogger.logWarning
+	  (Constants.ARITH_OP_NULL,
+	   getOperatorSymbol ());
+      }
+      return PrimitiveObjects.getInteger (0);
+    }
+
+    double left =
+      Coercions.coerceToPrimitiveNumber (pLeft, Double.class, pLogger).
+      doubleValue ();
+    double right =
+      Coercions.coerceToPrimitiveNumber (pRight, Double.class, pLogger).
+      doubleValue ();
+
+    try {
+      return PrimitiveObjects.getDouble (left / right);
+    }
+    catch (Exception exc) {
+      if (pLogger.isLoggingError ()) {
+	pLogger.logError
+	  (Constants.ARITH_ERROR,
+	   getOperatorSymbol (),
+	   "" + left,
+	   "" + right);
+      }
+      return PrimitiveObjects.getInteger (0);
+    }
+  }
+
+  //-------------------------------------
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/ELEvaluator.java b/standard/src/org/apache/taglibs/standard/lang/jstl/ELEvaluator.java
new file mode 100644
index 0000000..3db98e2
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/ELEvaluator.java
@@ -0,0 +1,473 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl;
+
+import java.io.Reader;
+import java.io.StringReader;
+import java.text.MessageFormat;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.taglibs.standard.lang.jstl.parser.ELParser;
+import org.apache.taglibs.standard.lang.jstl.parser.ParseException;
+import org.apache.taglibs.standard.lang.jstl.parser.Token;
+import org.apache.taglibs.standard.lang.jstl.parser.TokenMgrError;
+
+/**
+ *
+ * <p>This is the main class for evaluating expression Strings.  An
+ * expression String is a String that may contain expressions of the
+ * form ${...}.  Multiple expressions may appear in the same
+ * expression String.  In such a case, the expression String's value
+ * is computed by concatenating the String values of those evaluated
+ * expressions and any intervening non-expression text, then
+ * converting the resulting String to the expected type using the
+ * PropertyEditor mechanism.
+ *
+ * <p>In the special case where the expression String is a single
+ * expression, the value of the expression String is determined by
+ * evaluating the expression, without any intervening conversion to a
+ * String.
+ *
+ * <p>The evaluator maintains a cache mapping expression Strings to
+ * their parsed results.  For expression Strings containing no
+ * expression elements, it maintains a cache mapping
+ * ExpectedType/ExpressionString to parsed value, so that static
+ * expression Strings won't have to go through a conversion step every
+ * time they are used.  All instances of the evaluator share the same
+ * cache.  The cache may be bypassed by setting a flag on the
+ * evaluator's constructor.
+ *
+ * <p>The evaluator must be passed a VariableResolver in its
+ * constructor.  The VariableResolver is used to resolve variable
+ * names encountered in expressions, and can also be used to implement
+ * "implicit objects" that are always present in the namespace.
+ * Different applications will have different policies for variable
+ * lookups and implicit objects - these differences can be
+ * encapsulated in the VariableResolver passed to the evaluator's
+ * constructor.
+ *
+ * <p>Most VariableResolvers will need to perform their resolution
+ * against some context.  For example, a JSP environment needs a
+ * PageContext to resolve variables.  The evaluate() method takes a
+ * generic Object context which is eventually passed to the
+ * VariableResolver - the VariableResolver is responsible for casting
+ * the context to the proper type.
+ *
+ * <p>Once an evaluator instance has been constructed, it may be used
+ * multiple times, and may be used by multiple simultaneous Threads.
+ * In other words, an evaluator instance is well-suited for use as a
+ * singleton.
+ * 
+ * @author Nathan Abramson - Art Technology Group
+ * @author Shawn Bayern
+ * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: pierred $
+ **/
+
+public class ELEvaluator
+{
+  //-------------------------------------
+  // Properties
+  //-------------------------------------
+
+  //-------------------------------------
+  // Member variables
+  //-------------------------------------
+
+  /** The mapping from expression String to its parsed form (String,
+      Expression, or ExpressionString) **/
+  static Map sCachedExpressionStrings = 
+    Collections.synchronizedMap (new HashMap ());
+
+  /** The mapping from ExpectedType to Maps mapping literal String to
+      parsed value **/
+  static Map sCachedExpectedTypes = new HashMap ();
+
+  /** The static Logger **/
+  static Logger sLogger = new Logger (System.out);
+
+  /** The VariableResolver **/
+  VariableResolver mResolver;
+
+  /** Flag if the cache should be bypassed **/
+  boolean mBypassCache;
+
+  //-------------------------------------
+  /**
+   *
+   * Constructor
+   *
+   * @param pResolver the object that should be used to resolve
+   * variable names encountered in expressions.  If null, all variable
+   * references will resolve to null.
+   **/
+  public ELEvaluator (VariableResolver pResolver)
+  {
+    mResolver = pResolver;
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Constructor
+   *
+   * @param pResolver the object that should be used to resolve
+   * variable names encountered in expressions.  If null, all variable
+   * references will resolve to null.
+   *
+   * @param pBypassCache flag indicating if the cache should be
+   * bypassed
+   **/
+  public ELEvaluator (VariableResolver pResolver,
+		      boolean pBypassCache)
+  {
+    mResolver = pResolver;
+    mBypassCache = pBypassCache;
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Evaluates the given expression String
+   *
+   * @param pExpressionString the expression String to be evaluated
+   * @param pContext the context passed to the VariableResolver for
+   * resolving variable names
+   * @param pExpectedType the type to which the evaluated expression
+   * should be coerced
+   * @return the expression String evaluated to the given expected
+   * type
+   **/
+  public Object evaluate (String pExpressionString,
+			  Object pContext,
+			  Class pExpectedType,
+			  Map functions,
+			  String defaultPrefix)
+    throws ELException
+  {
+    return evaluate (pExpressionString,
+		     pContext,
+		     pExpectedType,
+		     functions,
+		     defaultPrefix,
+		     sLogger);
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Evaluates the given expression string
+   **/
+  Object evaluate (String pExpressionString,
+		   Object pContext,
+		   Class pExpectedType,
+		   Map functions,
+		   String defaultPrefix,
+		   Logger pLogger)
+    throws ELException
+  {
+    // Check for null expression strings
+    if (pExpressionString == null) {
+      throw new ELException
+	(Constants.NULL_EXPRESSION_STRING);
+    }
+
+    // Get the parsed version of the expression string
+    Object parsedValue = parseExpressionString (pExpressionString);
+
+    // Evaluate differently based on the parsed type
+    if (parsedValue instanceof String) {
+      // Convert the String, and cache the conversion
+      String strValue = (String) parsedValue;
+      return convertStaticValueToExpectedType (strValue, 
+					       pExpectedType, 
+					       pLogger);
+    }
+
+    else if (parsedValue instanceof Expression) {
+      // Evaluate the expression and convert
+      Object value = 
+	((Expression) parsedValue).evaluate (pContext,
+					     mResolver,
+					     functions,
+					     defaultPrefix,
+					     pLogger);
+      return convertToExpectedType (value, 
+				    pExpectedType,
+				    pLogger);
+    }
+
+    else if (parsedValue instanceof ExpressionString) {
+      // Evaluate the expression/string list and convert
+      String strValue = 
+	((ExpressionString) parsedValue).evaluate (pContext, 
+						   mResolver,
+						   functions,
+						   defaultPrefix,
+						   pLogger);
+      return convertToExpectedType (strValue,
+				    pExpectedType,
+				    pLogger);
+    }
+
+    else {
+      // This should never be reached
+      return null;
+    }
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Gets the parsed form of the given expression string.  If the
+   * parsed form is cached (and caching is not bypassed), return the
+   * cached form, otherwise parse and cache the value.  Returns either
+   * a String, Expression, or ExpressionString.
+   **/
+  public Object parseExpressionString (String pExpressionString)
+    throws ELException
+  {
+    // See if it's an empty String
+    if (pExpressionString.length () == 0) {
+      return "";
+    }
+
+    // See if it's in the cache
+    Object ret = 
+      mBypassCache ?
+      null :
+      sCachedExpressionStrings.get (pExpressionString);
+
+    if (ret == null) {
+      // Parse the expression
+      Reader r = new StringReader (pExpressionString);
+      ELParser parser = new ELParser (r);
+      try {
+	ret = parser.ExpressionString ();
+	sCachedExpressionStrings.put (pExpressionString, ret);
+      }
+      catch (ParseException exc) {
+	throw new ELException 
+	  (formatParseException (pExpressionString,
+				 exc));
+      }
+      catch (TokenMgrError exc) {
+	// Note - this should never be reached, since the parser is
+	// constructed to tokenize any input (illegal inputs get
+	// parsed to <BADLY_ESCAPED_STRING_LITERAL> or
+	// <ILLEGAL_CHARACTER>
+	throw new ELException (exc.getMessage ());
+      }
+    }
+    return ret;
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Converts the given value to the specified expected type.
+   **/
+  Object convertToExpectedType (Object pValue,
+				Class pExpectedType,
+				Logger pLogger)
+    throws ELException
+  {
+    return Coercions.coerce (pValue,
+			     pExpectedType,
+			     pLogger);
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Converts the given String, specified as a static expression
+   * string, to the given expected type.  The conversion is cached.
+   **/
+  Object convertStaticValueToExpectedType (String pValue,
+					   Class pExpectedType,
+					   Logger pLogger)
+    throws ELException
+  {
+    // See if the value is already of the expected type
+    if (pExpectedType == String.class ||
+	pExpectedType == Object.class) {
+      return pValue;
+    }
+
+    // Find the cached value
+    Map valueByString = getOrCreateExpectedTypeMap (pExpectedType);
+    if (!mBypassCache &&
+	valueByString.containsKey (pValue)) {
+      return valueByString.get (pValue);
+    }
+    else {
+      // Convert from a String
+      Object ret = Coercions.coerce (pValue, pExpectedType, pLogger);
+      valueByString.put (pValue, ret);
+      return ret;
+    }
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Creates or returns the Map that maps string literals to parsed
+   * values for the specified expected type.
+   **/
+  static Map getOrCreateExpectedTypeMap (Class pExpectedType)
+  {
+    synchronized (sCachedExpectedTypes) {
+      Map ret = (Map) sCachedExpectedTypes.get (pExpectedType);
+      if (ret == null) {
+	ret = Collections.synchronizedMap (new HashMap ());
+	sCachedExpectedTypes.put (pExpectedType, ret);
+      }
+      return ret;
+    }
+  }
+
+  //-------------------------------------
+  // Formatting ParseException
+  //-------------------------------------
+  /**
+   *
+   * Formats a ParseException into an error message suitable for
+   * displaying on a web page
+   **/
+  static String formatParseException (String pExpressionString,
+				      ParseException pExc)
+  {
+    // Generate the String of expected tokens
+    StringBuffer expectedBuf = new StringBuffer ();
+    int maxSize = 0;
+    boolean printedOne = false;
+
+    if (pExc.expectedTokenSequences == null)
+      return pExc.toString();
+
+    for (int i = 0; i < pExc.expectedTokenSequences.length; i++) {
+      if (maxSize < pExc.expectedTokenSequences [i].length) {
+        maxSize = pExc.expectedTokenSequences [i].length;
+      }
+      for (int j = 0; j < pExc.expectedTokenSequences [i].length; j++) {
+	if (printedOne) {
+	  expectedBuf.append (", ");
+	}
+        expectedBuf.append 
+	  (pExc.tokenImage [pExc.expectedTokenSequences [i] [j]]);
+	printedOne = true;
+      }
+    }
+    String expected = expectedBuf.toString ();
+
+    // Generate the String of encountered tokens
+    StringBuffer encounteredBuf = new StringBuffer ();
+    Token tok = pExc.currentToken.next;
+    for (int i = 0; i < maxSize; i++) {
+      if (i != 0) encounteredBuf.append (" ");
+      if (tok.kind == 0) {
+        encounteredBuf.append (pExc.tokenImage [0]);
+        break;
+      }
+      encounteredBuf.append (addEscapes (tok.image));
+      tok = tok.next; 
+    }
+    String encountered = encounteredBuf.toString ();
+
+    // Format the error message
+    return MessageFormat.format
+      (Constants.PARSE_EXCEPTION,
+       new Object [] {
+	 expected,
+	 encountered,
+       });
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Used to convert raw characters to their escaped version when
+   * these raw version cannot be used as part of an ASCII string
+   * literal.
+   **/
+  static String addEscapes (String str)
+  {
+    StringBuffer retval = new StringBuffer ();
+    char ch;
+    for (int i = 0; i < str.length (); i++) {
+      switch (str.charAt (i)) {
+	case 0 :
+	  continue;
+	case '\b':
+	  retval.append ("\\b");
+	  continue;
+	case '\t':
+	  retval.append ("\\t");
+	  continue;
+	case '\n':
+	  retval.append ("\\n");
+	  continue;
+	case '\f':
+	  retval.append ("\\f");
+	  continue;
+	case '\r':
+	  retval.append ("\\r");
+	  continue;
+	default:
+	  if ((ch = str.charAt (i)) < 0x20 || ch > 0x7e) {
+	    String s = "0000" + Integer.toString (ch, 16);
+	    retval.append ("\\u" + s.substring (s.length () - 4, s.length ()));
+	  }
+	  else {
+	    retval.append (ch);
+	  }
+	  continue;
+        }
+    }
+    return retval.toString ();
+  }
+
+  //-------------------------------------
+  // Testing methods
+  //-------------------------------------
+  /**
+   *
+   * Parses the given expression string, then converts it back to a
+   * String in its canonical form.  This is used to test parsing.
+   **/
+  public String parseAndRender (String pExpressionString)
+    throws ELException
+  {
+    Object val = parseExpressionString (pExpressionString);
+    if (val instanceof String) {
+      return (String) val;
+    }
+    else if (val instanceof Expression) {
+      return "${" + ((Expression) val).getExpressionString () + "}";
+    }
+    else if (val instanceof ExpressionString) {
+      return ((ExpressionString) val).getExpressionString ();
+    }
+    else {
+      return "";
+    }
+  }
+
+  //-------------------------------------
+
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/ELException.java b/standard/src/org/apache/taglibs/standard/lang/jstl/ELException.java
new file mode 100644
index 0000000..816a0c7
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/ELException.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl;
+
+
+/**
+ *
+ * Represents any of the exception conditions that arise during the
+ * operation evaluation of the evaluator.
+ * 
+ * @author Nathan Abramson - Art Technology Group
+ * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: pierred $
+ **/
+
+public class ELException
+  extends Exception
+{
+  //-------------------------------------
+  // Member variables
+  //-------------------------------------
+
+  Throwable mRootCause;
+
+  //-------------------------------------
+  /**
+   *
+   * Constructor
+   **/
+  public ELException ()
+  {
+    super ();
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Constructor
+   **/
+  public ELException (String pMessage)
+  {
+    super (pMessage);
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Constructor
+   **/
+  public ELException (Throwable pRootCause)
+  {
+    mRootCause = pRootCause;
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Constructor
+   **/
+  public ELException (String pMessage,
+		      Throwable pRootCause)
+  {
+    super (pMessage);
+    mRootCause = pRootCause;
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Returns the root cause
+   **/
+  public Throwable getRootCause ()
+  {
+    return mRootCause;
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * String representation
+   **/
+  public String toString ()
+  {
+    if (getMessage () == null) {
+      return mRootCause.toString ();
+    }
+    else if (mRootCause == null) {
+      return getMessage ();
+    }
+    else {
+      return getMessage () + ": " + mRootCause;
+    }
+  }
+
+  //-------------------------------------
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/ELParser.jj b/standard/src/org/apache/taglibs/standard/lang/jstl/ELParser.jj
new file mode 100644
index 0000000..ed9e732
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/ELParser.jj
@@ -0,0 +1,781 @@
+/*****************************************
+ * OPTIONS *
+ *****************************************/
+
+options {
+  JAVA_UNICODE_ESCAPE = false;
+  UNICODE_INPUT = true;
+  STATIC = false;
+}
+
+/*****************************************
+ * PARSER JAVA CODE *
+ *****************************************/
+
+PARSER_BEGIN(ELParser)
+
+package org.apache.taglibs.standard.lang.jstl.parser;
+
+import org.apache.taglibs.standard.lang.jstl.*;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Generated EL parser.
+ * 
+ * @author Nathan Abramson
+ * @author Shawn Bayern
+ */
+
+public class ELParser {
+
+  public static void main(String args[]) 
+       throws ParseException
+  {
+    ELParser parser = new ELParser (System.in);
+    parser.ExpressionString ();
+  }
+
+}
+
+PARSER_END(ELParser)
+
+
+/*****************************************
+ * TOKENS *
+ *****************************************/
+
+
+/*****************************************
+/** Tokens appearing outside of an ${...} construct **/
+
+<DEFAULT> TOKEN:
+{
+  < NON_EXPRESSION_TEXT:
+    (~["$"])+ | ("$" (~["{", "$"])+) | "$"
+  >
+|
+  < START_EXPRESSION: "${" > : IN_EXPRESSION
+}
+
+/*****************************************
+/** Tokens appearing inside of an ${...} construct **/
+
+/* WHITE SPACE */
+
+<IN_EXPRESSION> SKIP :
+{
+  " "
+| "\t"
+| "\n"
+| "\r"
+}
+
+<IN_EXPRESSION> TOKEN :
+{
+/* Literals */
+
+  < INTEGER_LITERAL: ["0"-"9"] (["0"-"9"])* >
+|
+  < FLOATING_POINT_LITERAL:
+        (["0"-"9"])+ "." (["0"-"9"])* (<EXPONENT>)?
+      | "." (["0"-"9"])+ (<EXPONENT>)?
+      | (["0"-"9"])+ <EXPONENT>
+  >
+|
+  < #EXPONENT: ["e","E"] (["+","-"])? (["0"-"9"])+ >
+|
+  < STRING_LITERAL:
+      ("\"" ((~["\"","\\"]) | ("\\" ( ["\\","\""] )))* "\"") |
+      ("\'" ((~["\'","\\"]) | ("\\" ( ["\\","\'"] )))* "\'")
+  >
+|
+  < BADLY_ESCAPED_STRING_LITERAL:
+      ("\"" (~["\"","\\"])* ("\\" ( ~["\\","\""] ))) |
+      ("\'" (~["\'","\\"])* ("\\" ( ~["\\","\'"] )))
+  >
+
+/* Reserved Words and Symbols */
+
+| < TRUE: "true" >
+| < FALSE: "false" >
+| < NULL: "null" >
+| < END_EXPRESSION: "}" > : DEFAULT
+| < DOT: "." >
+| < GT1: ">" >
+| < GT2: "gt" >
+| < LT1: "<" >
+| < LT2: "lt" >
+| < EQ1: "==" >
+| < EQ2: "eq" >
+| < LE1: "<=" >
+| < LE2: "le" >
+| < GE1: ">=" >
+| < GE2: "ge" >
+| < NE1: "!=" >
+| < NE2: "ne" >
+| < LPAREN: "(" >
+| < RPAREN: ")" >
+| < COMMA: "," >
+| < COLON: ":" >
+| < LBRACKET: "[" >
+| < RBRACKET: "]" >
+| < PLUS: "+" >
+| < MINUS: "-" >
+| < MULTIPLY: "*" >
+| < DIVIDE1: "/" >
+| < DIVIDE2: "div" >
+| < MODULUS1: "%" >
+| < MODULUS2: "mod" >
+| < NOT1: "not" >
+| < NOT2: "!" >
+| < AND1: "and" >
+| < AND2: "&&" >
+| < OR1: "or" >
+| < OR2: "||" >
+| < EMPTY: "empty" >
+
+
+/* Identifiers */
+
+| < IDENTIFIER: (<LETTER>|<IMPL_OBJ_START>) (<LETTER>|<DIGIT>)* >
+| < #IMPL_OBJ_START: "#" >
+|
+  < #LETTER:
+      [
+       "\u0024",
+       "\u0041"-"\u005a",
+       "\u005f",
+       "\u0061"-"\u007a",
+       "\u00c0"-"\u00d6",
+       "\u00d8"-"\u00f6",
+       "\u00f8"-"\u00ff",
+       "\u0100"-"\u1fff",
+       "\u3040"-"\u318f",
+       "\u3300"-"\u337f",
+       "\u3400"-"\u3d2d",
+       "\u4e00"-"\u9fff",
+       "\uf900"-"\ufaff"
+      ]
+  >
+|
+  < #DIGIT:
+      [
+       "\u0030"-"\u0039",
+       "\u0660"-"\u0669",
+       "\u06f0"-"\u06f9",
+       "\u0966"-"\u096f",
+       "\u09e6"-"\u09ef",
+       "\u0a66"-"\u0a6f",
+       "\u0ae6"-"\u0aef",
+       "\u0b66"-"\u0b6f",
+       "\u0be7"-"\u0bef",
+       "\u0c66"-"\u0c6f",
+       "\u0ce6"-"\u0cef",
+       "\u0d66"-"\u0d6f",
+       "\u0e50"-"\u0e59",
+       "\u0ed0"-"\u0ed9",
+       "\u1040"-"\u1049"
+      ]
+  >
+
+/* This is used to catch any non-matching tokens, so as to avoid any
+   TokenMgrErrors */
+| < ILLEGAL_CHARACTER: (~[]) >
+}
+
+
+/*****************************************
+ * GRAMMAR PRODUCTIONS *
+ *****************************************/
+
+/**
+ *
+ * Returns a String if the expression string is a single String, an
+ * Expression if the expression string is a single Expression, an
+ * ExpressionString if it's a mixture of both.
+ **/
+Object ExpressionString () :
+{
+  Object ret = "";
+  List elems = null;
+  Object elem;
+}
+{
+  /** Try to optimize for the case of a single expression or String **/
+  (ret = AttrValueString () | ret = AttrValueExpression ())
+
+
+  /** If there's more than one, then switch to using a List **/
+  (
+    (elem = AttrValueString () | elem = AttrValueExpression ())
+     {
+       if (elems == null) {
+         elems = new ArrayList ();
+	 elems.add (ret);
+       }
+       elems.add (elem);
+     }
+  )*
+
+  {
+    if (elems != null) {
+      ret = new ExpressionString (elems.toArray ());
+    }
+    return ret;
+  }
+}
+
+
+String AttrValueString () :
+{
+  Token t;
+}
+{
+  t = <NON_EXPRESSION_TEXT>
+  { return t.image; }
+}
+
+
+Expression AttrValueExpression () :
+{
+  Expression exp;
+}
+{
+  <START_EXPRESSION> exp = Expression () <END_EXPRESSION>
+   { return exp; }
+}
+
+
+Expression Expression () :
+{
+  Expression ret;
+}
+{
+  ret = OrExpression ()
+  { return ret; }
+}
+
+
+Expression OrExpression () :
+{
+  Expression startExpression;
+  BinaryOperator operator;
+  Expression expression;
+  List operators = null;
+  List expressions = null;
+}
+{
+  startExpression = AndExpression ()
+
+    (
+     (
+      (<OR1> | <OR2>) { operator = OrOperator.SINGLETON; }
+      )
+     expression = AndExpression ()
+
+      {
+	if (operators == null) {
+	  operators = new ArrayList ();
+	  expressions = new ArrayList ();
+	}
+	operators.add (operator);
+	expressions.add (expression);
+      }
+     )*
+
+  {
+    if (operators != null) {
+      return new BinaryOperatorExpression (startExpression,
+					   operators,
+					   expressions);
+    }
+    else {
+      return startExpression;
+    }
+  }
+}
+
+
+Expression AndExpression () :
+{
+  Expression startExpression;
+  BinaryOperator operator;
+  Expression expression;
+  List operators = null;
+  List expressions = null;
+}
+{
+  startExpression = EqualityExpression ()
+
+    (
+     (
+      (<AND1> | <AND2>) { operator = AndOperator.SINGLETON; }
+      )
+     expression = EqualityExpression ()
+
+      {
+	if (operators == null) {
+	  operators = new ArrayList ();
+	  expressions = new ArrayList ();
+	}
+	operators.add (operator);
+	expressions.add (expression);
+      }
+     )*
+
+  {
+    if (operators != null) {
+      return new BinaryOperatorExpression (startExpression,
+					   operators,
+					   expressions);
+    }
+    else {
+      return startExpression;
+    }
+  }
+}
+
+
+Expression EqualityExpression () :
+{
+  Expression startExpression;
+  BinaryOperator operator;
+  Expression expression;
+  List operators = null;
+  List expressions = null;
+}
+{
+  startExpression = RelationalExpression ()
+
+    (
+     (
+      (<EQ1> | <EQ2>) { operator = EqualsOperator.SINGLETON; }
+      | (<NE1> | <NE2>) { operator = NotEqualsOperator.SINGLETON; }
+      )
+     expression = RelationalExpression ()
+
+      {
+	if (operators == null) {
+	  operators = new ArrayList ();
+	  expressions = new ArrayList ();
+	}
+	operators.add (operator);
+	expressions.add (expression);
+      }
+     )*
+
+  {
+    if (operators != null) {
+      return new BinaryOperatorExpression (startExpression,
+					   operators,
+					   expressions);
+    }
+    else {
+      return startExpression;
+    }
+  }
+}
+
+
+Expression RelationalExpression () :
+{
+  Expression startExpression;
+  BinaryOperator operator;
+  Expression expression;
+  List operators = null;
+  List expressions = null;
+}
+{
+  startExpression = AddExpression ()
+
+    (
+     (
+      (<LT1> | <LT2>) { operator = LessThanOperator.SINGLETON; }
+      | (<GT1> | <GT2>) { operator = GreaterThanOperator.SINGLETON; }
+      | (<GE1> | <GE2>) { operator = GreaterThanOrEqualsOperator.SINGLETON; }
+      | (<LE1> | <LE2>) { operator = LessThanOrEqualsOperator.SINGLETON; }
+      )
+     expression = AddExpression ()
+
+      {
+	if (operators == null) {
+	  operators = new ArrayList ();
+	  expressions = new ArrayList ();
+	}
+	operators.add (operator);
+	expressions.add (expression);
+      }
+     )*
+
+  {
+    if (operators != null) {
+      return new BinaryOperatorExpression (startExpression,
+					   operators,
+					   expressions);
+    }
+    else {
+      return startExpression;
+    }
+  }
+}
+
+
+Expression AddExpression () :
+{
+  Expression startExpression;
+  BinaryOperator operator;
+  Expression expression;
+  List operators = null;
+  List expressions = null;
+}
+{
+  startExpression = MultiplyExpression ()
+
+    (
+     (
+      <PLUS> { operator = PlusOperator.SINGLETON; }
+      | <MINUS> { operator = MinusOperator.SINGLETON; }
+      )
+     expression = MultiplyExpression ()
+
+      {
+	if (operators == null) {
+	  operators = new ArrayList ();
+	  expressions = new ArrayList ();
+	}
+	operators.add (operator);
+	expressions.add (expression);
+      }
+     )*
+
+  {
+    if (operators != null) {
+      return new BinaryOperatorExpression (startExpression,
+					   operators,
+					   expressions);
+    }
+    else {
+      return startExpression;
+    }
+  }
+}
+
+
+Expression MultiplyExpression () :
+{
+  Expression startExpression;
+  BinaryOperator operator;
+  Expression expression;
+  List operators = null;
+  List expressions = null;
+}
+{
+  startExpression = UnaryExpression ()
+
+    (
+     (
+      <MULTIPLY> { operator = MultiplyOperator.SINGLETON; }
+      | (<DIVIDE1> | <DIVIDE2>) { operator = DivideOperator.SINGLETON; }
+      | (<MODULUS1> | <MODULUS2>) { operator = ModulusOperator.SINGLETON; }
+      )
+     expression = UnaryExpression ()
+
+      {
+	if (operators == null) {
+	  operators = new ArrayList ();
+	  expressions = new ArrayList ();
+	}
+	operators.add (operator);
+	expressions.add (expression);
+      }
+     )*
+
+  {
+    if (operators != null) {
+      return new BinaryOperatorExpression (startExpression,
+					   operators,
+					   expressions);
+    }
+    else {
+      return startExpression;
+    }
+  }
+}
+
+
+Expression UnaryExpression () :
+{
+  Expression expression;
+  UnaryOperator singleOperator = null;
+  UnaryOperator operator;
+  List operators = null;
+}
+{
+  (
+   (
+    (<NOT1> | <NOT2>) { operator = NotOperator.SINGLETON; }
+    | <MINUS> { operator = UnaryMinusOperator.SINGLETON; }
+    | <EMPTY> { operator = EmptyOperator.SINGLETON; }
+    )
+  {
+    if (singleOperator == null) {
+      singleOperator = operator;
+    }
+    else if (operators == null) {
+      operators = new ArrayList ();
+      operators.add (singleOperator);
+      operators.add (operator);
+    }
+    else {
+      operators.add (operator);
+    }
+  }
+   )*
+
+    expression = Value ()
+
+  {
+    if (operators != null) {
+      return new UnaryOperatorExpression (null, operators, expression);
+    }
+    else if (singleOperator != null) {
+      return new UnaryOperatorExpression (singleOperator, null, expression);
+    }
+    else {
+      return expression;
+    }
+  }
+}
+
+
+Expression Value () :
+{
+  Expression prefix;
+  ValueSuffix suffix;
+  List suffixes = null;
+}
+{
+  prefix = ValuePrefix ()
+    (suffix = ValueSuffix () 
+      { 
+	if (suffixes == null) {
+	  suffixes = new ArrayList ();
+	}
+	suffixes.add (suffix);
+      }
+     )*
+
+  {
+    if (suffixes == null) {
+      return prefix;
+    }
+    else {
+      return new ComplexValue (prefix, suffixes);
+    }
+  }
+}
+
+
+/**
+ * This is an element that can start a value
+ **/
+Expression ValuePrefix () :
+{
+  Expression ret;
+}
+{
+  (
+   ret = Literal ()
+   | <LPAREN> ret = Expression () <RPAREN>
+   | LOOKAHEAD(QualifiedName() <LPAREN>) ret = FunctionInvocation ()
+   | ret = NamedValue ()
+   )
+    { return ret; }
+}
+
+
+NamedValue NamedValue () :
+{
+  Token t;
+}
+{
+  t = <IDENTIFIER> { return new NamedValue (t.image); }
+}
+
+
+FunctionInvocation FunctionInvocation () :
+{
+  String qualifiedName;
+  List argumentList = new ArrayList();
+  Expression exp;
+}
+{
+  (
+   qualifiedName = QualifiedName()
+   <LPAREN>
+    (
+      (
+        exp = Expression ()
+        {
+          argumentList.add(exp);
+        }
+      )
+      (
+        <COMMA>
+        exp = Expression ()
+        {
+          argumentList.add(exp);
+        }
+      )*
+    )?
+   <RPAREN>
+  )
+  {
+    String allowed = System.getProperty("javax.servlet.jsp.functions.allowed");
+    if (allowed == null || !allowed.equalsIgnoreCase("true"))
+      throw new ParseException("EL functions are not supported.");
+    return new FunctionInvocation(qualifiedName, argumentList);
+  }
+}
+
+
+ValueSuffix ValueSuffix () :
+{
+  ValueSuffix suffix;
+}
+{
+  (
+   suffix = PropertySuffix ()
+   | suffix = ArraySuffix ()
+   )
+
+    { return suffix; }
+}
+
+
+PropertySuffix PropertySuffix () :
+{
+  Token t;
+  String property;
+}
+{
+  <DOT> 
+     (property = Identifier ())
+
+    {
+      return new PropertySuffix (property);
+    }
+}
+
+
+ArraySuffix ArraySuffix () :
+{
+  Expression index;
+}
+{
+  <LBRACKET>
+     index = Expression ()
+     <RBRACKET>
+   
+   {
+     return new ArraySuffix (index);
+   }
+}
+
+
+Literal Literal () :
+{
+  Literal ret;
+}
+{
+  (
+   ret = BooleanLiteral ()
+   | ret = IntegerLiteral ()
+   | ret = FloatingPointLiteral ()
+   | ret = StringLiteral ()
+   | ret = NullLiteral ()
+   )
+    { return ret; }
+}
+
+
+BooleanLiteral BooleanLiteral () :
+{
+}
+{
+  <TRUE> { return BooleanLiteral.TRUE; }
+  | <FALSE> { return BooleanLiteral.FALSE; }
+}
+
+
+StringLiteral StringLiteral () :
+{
+  Token t;
+}
+{
+  t = <STRING_LITERAL>
+  { return StringLiteral.fromToken (t.image); }
+}
+
+
+IntegerLiteral IntegerLiteral () :
+{
+  Token t;
+}
+{
+  t = <INTEGER_LITERAL>
+  { return new IntegerLiteral (t.image); }
+}
+
+
+FloatingPointLiteral FloatingPointLiteral () :
+{
+  Token t;
+}
+{
+  t = <FLOATING_POINT_LITERAL>
+  { return new FloatingPointLiteral (t.image); }
+}
+
+
+NullLiteral NullLiteral () :
+{
+}
+{
+  <NULL>
+    { return NullLiteral.SINGLETON; }
+}
+
+
+String Identifier () :
+{
+  Token t;
+}
+{
+  (
+   t = <IDENTIFIER>
+   )
+    { return t.image; }
+}
+
+String QualifiedName () :
+{
+  String prefix = null, localPart = null;
+}
+{
+  (
+    (
+      LOOKAHEAD(Identifier() <COLON>)
+      prefix = Identifier ()
+      <COLON>
+    )?
+    localPart = Identifier ()
+  )
+  {
+    if (prefix == null)
+      return localPart;
+    else
+     return prefix + ":" + localPart;
+  }
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/EmptyOperator.java b/standard/src/org/apache/taglibs/standard/lang/jstl/EmptyOperator.java
new file mode 100644
index 0000000..dceecde
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/EmptyOperator.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl;
+
+import java.lang.reflect.Array;
+import java.util.List;
+import java.util.Map;
+
+/**
+ *
+ * <p>The implementation of the empty operator
+ * 
+ * @author Nathan Abramson - Art Technology Group
+ * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: pierred $
+ **/
+
+public class EmptyOperator
+  extends UnaryOperator
+{
+  //-------------------------------------
+  // Singleton
+  //-------------------------------------
+
+  public static final EmptyOperator SINGLETON =
+    new EmptyOperator ();
+
+  //-------------------------------------
+  /**
+   *
+   * Constructor
+   **/
+  public EmptyOperator ()
+  {
+  }
+
+  //-------------------------------------
+  // Expression methods
+  //-------------------------------------
+  /**
+   *
+   * Returns the symbol representing the operator
+   **/
+  public String getOperatorSymbol ()
+  {
+    return "empty";
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Applies the operator to the given value
+   **/
+  public Object apply (Object pValue,
+		       Object pContext,
+		       Logger pLogger)
+    throws ELException
+  {
+    // See if the value is null
+    if (pValue == null) {
+      return PrimitiveObjects.getBoolean (true);
+    }
+
+    // See if the value is a zero-length String
+    else if ("".equals (pValue)) {
+      return PrimitiveObjects.getBoolean (true);
+    }
+
+    // See if the value is a zero-length array
+    else if (pValue.getClass ().isArray () &&
+	     Array.getLength (pValue) == 0) {
+      return PrimitiveObjects.getBoolean (true);
+    }
+
+    // See if the value is an empty List
+    else if (pValue instanceof List &&
+	     ((List) pValue).isEmpty ()) {
+      return PrimitiveObjects.getBoolean (true);
+    }
+
+    // See if the value is an empty Map
+    else if (pValue instanceof Map &&
+	     ((Map) pValue).isEmpty ()) {
+      return PrimitiveObjects.getBoolean (true);
+    }
+
+    // Otherwise, not empty
+    else {
+      return PrimitiveObjects.getBoolean (false);
+    }
+  }
+
+  //-------------------------------------
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/EnumeratedMap.java b/standard/src/org/apache/taglibs/standard/lang/jstl/EnumeratedMap.java
new file mode 100644
index 0000000..06583f5
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/EnumeratedMap.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl;
+
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ *
+ * <p>This is a Map implementation driven by a data source that only
+ * provides an enumeration of keys and a getValue(key) method.  This
+ * class must be subclassed to implement those methods.
+ *
+ * <p>Some of the methods may incur a performance penalty that
+ * involves enumerating the entire data source.  In these cases, the
+ * Map will try to save the results of that enumeration, but only if
+ * the underlying data source is immutable.
+ * 
+ * @author Nathan Abramson - Art Technology Group
+ * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: pierred $
+ **/
+
+public abstract class EnumeratedMap
+  implements Map
+{
+  //-------------------------------------
+  // Member variables
+  //-------------------------------------
+
+  Map mMap;
+
+  //-------------------------------------
+  public void clear ()
+  {
+    throw new UnsupportedOperationException ();
+  }
+
+  //-------------------------------------
+  public boolean containsKey (Object pKey)
+  {
+    return getValue (pKey) != null;
+  }
+
+  //-------------------------------------
+  public boolean containsValue (Object pValue)
+  {
+    return getAsMap ().containsValue (pValue);
+  }
+
+  //-------------------------------------
+  public Set entrySet ()
+  {
+    return getAsMap ().entrySet ();
+  }
+
+  //-------------------------------------
+  public Object get (Object pKey)
+  {
+    return getValue (pKey);
+  }
+
+  //-------------------------------------
+  public boolean isEmpty ()
+  {
+    return !enumerateKeys ().hasMoreElements ();
+  }
+
+  //-------------------------------------
+  public Set keySet ()
+  {
+    return getAsMap ().keySet ();
+  }
+
+  //-------------------------------------
+  public Object put (Object pKey, Object pValue)
+  {
+    throw new UnsupportedOperationException ();
+  }
+
+  //-------------------------------------
+  public void putAll (Map pMap)
+  {
+    throw new UnsupportedOperationException ();
+  }
+
+  //-------------------------------------
+  public Object remove (Object pKey)
+  {
+    throw new UnsupportedOperationException ();
+  }
+
+  //-------------------------------------
+  public int size ()
+  {
+    return getAsMap ().size ();
+  }
+
+  //-------------------------------------
+  public Collection values ()
+  {
+    return getAsMap ().values ();
+  }
+
+  //-------------------------------------
+  // Abstract methods
+  //-------------------------------------
+  /**
+   *
+   * Returns an enumeration of the keys
+   **/
+  public abstract Enumeration enumerateKeys ();
+
+  //-------------------------------------
+  /**
+   *
+   * Returns true if it is possible for this data source to change
+   **/
+  public abstract boolean isMutable ();
+
+  //-------------------------------------
+  /**
+   *
+   * Returns the value associated with the given key, or null if not
+   * found.
+   **/
+  public abstract Object getValue (Object pKey);
+
+  //-------------------------------------
+  /**
+   *
+   * Converts the MapSource to a Map.  If the map is not mutable, this
+   * is cached
+   **/
+  public Map getAsMap ()
+  {
+    if (mMap != null) {
+      return mMap;
+    }
+    else {
+      Map m = convertToMap ();
+      if (!isMutable ()) {
+	mMap = m;
+      }
+      return m;
+    }
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Converts to a Map
+   **/
+  Map convertToMap ()
+  {
+    Map ret = new HashMap ();
+    for (Enumeration e = enumerateKeys (); e.hasMoreElements (); ) {
+      Object key = e.nextElement ();
+      Object value = getValue (key);
+      ret.put (key, value);
+    }
+    return ret;
+  }
+
+  //-------------------------------------
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/EqualityOperator.java b/standard/src/org/apache/taglibs/standard/lang/jstl/EqualityOperator.java
new file mode 100644
index 0000000..39763b2
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/EqualityOperator.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl;
+
+/**
+ *
+ * <p>This is the superclass for all equality operators (==, !=)
+ * 
+ * @author Nathan Abramson - Art Technology Group
+ * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: pierred $
+ **/
+
+public abstract class EqualityOperator
+  extends BinaryOperator
+{
+  //-------------------------------------
+  /**
+   *
+   * Applies the operator to the given value
+   **/
+  public Object apply (Object pLeft,
+		       Object pRight,
+		       Object pContext,
+		       Logger pLogger)
+    throws ELException
+  {
+    return Coercions.applyEqualityOperator (pLeft, pRight, this, pLogger);
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Applies the operator given the fact that the two elements are
+   * equal.
+   **/
+  public abstract boolean apply (boolean pAreEqual,
+				 Logger pLogger);
+  
+  //-------------------------------------
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/EqualsOperator.java b/standard/src/org/apache/taglibs/standard/lang/jstl/EqualsOperator.java
new file mode 100644
index 0000000..d722a1a
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/EqualsOperator.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl;
+
+/**
+ *
+ * <p>The implementation of the equals operator
+ * 
+ * @author Nathan Abramson - Art Technology Group
+ * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: pierred $
+ **/
+
+public class EqualsOperator
+  extends EqualityOperator
+{
+  //-------------------------------------
+  // Singleton
+  //-------------------------------------
+
+  public static final EqualsOperator SINGLETON =
+    new EqualsOperator ();
+
+  //-------------------------------------
+  /**
+   *
+   * Constructor
+   **/
+  public EqualsOperator ()
+  {
+  }
+
+  //-------------------------------------
+  // Expression methods
+  //-------------------------------------
+  /**
+   *
+   * Returns the symbol representing the operator
+   **/
+  public String getOperatorSymbol ()
+  {
+    return "==";
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Applies the operator given the fact that the two elements are
+   * equal.
+   **/
+  public boolean apply (boolean pAreEqual,
+			Logger pLogger)
+  {
+    return pAreEqual;
+  }
+  
+  //-------------------------------------
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/Evaluator.java b/standard/src/org/apache/taglibs/standard/lang/jstl/Evaluator.java
new file mode 100644
index 0000000..8d1f53d
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/Evaluator.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl;
+
+import java.text.MessageFormat;
+import java.util.Map;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.PageContext;
+import javax.servlet.jsp.tagext.Tag;
+
+import org.apache.taglibs.standard.lang.support.ExpressionEvaluator;
+
+/**
+ *
+ * <p>This is the expression evaluator "adapter" that customizes it
+ * for use with the JSP Standard Tag Library.  It uses a
+ * VariableResolver implementation that looks up variables from the
+ * PageContext and also implements its implicit objects.  It also
+ * wraps ELExceptions in JspExceptions that describe the attribute
+ * name and value causing the error.
+ * 
+ * @author Nathan Abramson - Art Technology Group
+ * @author Shawn Bayern
+ * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: pierred $
+ **/
+
+public class Evaluator
+  implements ExpressionEvaluator
+{
+  //-------------------------------------
+  // Properties
+  //-------------------------------------
+
+  //-------------------------------------
+  // Member variables
+  //-------------------------------------
+
+  /** The singleton instance of the evaluator **/
+  static ELEvaluator sEvaluator =
+    new ELEvaluator
+    (new JSTLVariableResolver ());
+
+  //-------------------------------------
+  // ExpressionEvaluator methods
+  //-------------------------------------
+  /** 
+   *
+   * Translation time validation of an attribute value.  This method
+   * will return a null String if the attribute value is valid;
+   * otherwise an error message.
+   **/ 
+  public String validate (String pAttributeName,
+			  String pAttributeValue)
+  {
+    try {
+      sEvaluator.parseExpressionString (pAttributeValue);
+      return null;
+    }
+    catch (ELException exc) {
+      return
+	MessageFormat.format
+	(Constants.ATTRIBUTE_PARSE_EXCEPTION,
+	 new Object [] {
+	   "" + pAttributeName,
+	   "" + pAttributeValue,
+	   exc.getMessage ()
+	 });
+    }
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Evaluates the expression at request time
+   **/
+  public Object evaluate (String pAttributeName,
+			  String pAttributeValue,
+			  Class pExpectedType,
+			  Tag pTag,
+			  PageContext pPageContext,
+			  Map functions,
+			  String defaultPrefix)
+    throws JspException
+  {
+    try {
+      return sEvaluator.evaluate
+	(pAttributeValue,
+	 pPageContext,
+	 pExpectedType,
+	 functions,
+	 defaultPrefix);
+    }
+    catch (ELException exc) {
+      throw new JspException
+	(MessageFormat.format
+	 (Constants.ATTRIBUTE_EVALUATION_EXCEPTION,
+	  new Object [] {
+	    "" + pAttributeName,
+	    "" + pAttributeValue,
+	    exc.getMessage(),
+	    exc.getRootCause()
+	  }), exc.getRootCause());
+    }
+  }
+
+  /** Conduit to old-style call for convenience. */
+  public Object evaluate (String pAttributeName,
+			  String pAttributeValue,
+			  Class pExpectedType,
+			  Tag pTag,
+			  PageContext pPageContext)
+    throws JspException
+  {
+    return evaluate(pAttributeName,
+		   pAttributeValue,
+		   pExpectedType,
+		   pTag,
+		   pPageContext,
+		   null,
+		   null);
+  }
+
+
+  //-------------------------------------
+  // Testing methods
+  //-------------------------------------
+  /**
+   *
+   * Parses the given attribute value, then converts it back to a
+   * String in its canonical form.
+   **/
+  public static String parseAndRender (String pAttributeValue)
+    throws JspException
+  {
+    try {
+      return sEvaluator.parseAndRender (pAttributeValue);
+    }
+    catch (ELException exc) {
+      throw new JspException
+	(MessageFormat.format
+	 (Constants.ATTRIBUTE_PARSE_EXCEPTION,
+	  new Object [] {
+	    "test",
+	    "" + pAttributeValue,
+	    exc.getMessage ()
+	  }));
+    }
+  }
+
+  //-------------------------------------
+
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/Expression.java b/standard/src/org/apache/taglibs/standard/lang/jstl/Expression.java
new file mode 100644
index 0000000..f87e08d
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/Expression.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl;
+
+import java.util.Map;
+
+/**
+ *
+ * <p>The abstract class from which all expression types
+ * derive.
+ * 
+ * @author Nathan Abramson - Art Technology Group
+ * @author Shawn Bayern
+ * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: pierred $
+ **/
+
+public abstract class Expression
+{
+  //-------------------------------------
+  // Member variables
+  //-------------------------------------
+
+  //-------------------------------------
+  /**
+   *
+   * Returns the expression in the expression language syntax
+   **/
+  public abstract String getExpressionString ();
+
+  //-------------------------------------
+  /**
+   *
+   * Evaluates the expression in the given context
+   **/
+  public abstract Object evaluate (Object pContext,
+				   VariableResolver pResolver,
+				   Map functions,
+				   String defaultPrefix,
+				   Logger pLogger)
+    throws ELException;
+
+  //-------------------------------------
+
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/ExpressionString.java b/standard/src/org/apache/taglibs/standard/lang/jstl/ExpressionString.java
new file mode 100644
index 0000000..2c61e09
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/ExpressionString.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl;
+
+import java.util.Map;
+
+/**
+ *
+ * <p>Represents an expression String consisting of a mixture of
+ * Strings and Expressions.
+ * 
+ * @author Nathan Abramson - Art Technology Group
+ * @author Shawn Bayern
+ * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: pierred $
+ **/
+
+public class ExpressionString
+{
+  //-------------------------------------
+  // Properties
+  //-------------------------------------
+  // property elements
+
+  Object [] mElements;
+  public Object [] getElements ()
+  { return mElements; }
+  public void setElements (Object [] pElements)
+  { mElements = pElements; }
+
+  //-------------------------------------
+  /**
+   *
+   * Constructor
+   **/
+  public ExpressionString (Object [] pElements)
+  {
+    mElements = pElements;
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Evaluates the expression string by evaluating each element,
+   * converting it to a String (using toString, or "" for null values)
+   * and concatenating the results into a single String.
+   **/
+  public String evaluate (Object pContext,
+			  VariableResolver pResolver,
+			  Map functions,
+			  String defaultPrefix,
+			  Logger pLogger)
+    throws ELException
+  {
+    StringBuffer buf = new StringBuffer ();
+    for (int i = 0; i < mElements.length; i++) {
+      Object elem = mElements [i];
+      if (elem instanceof String) {
+	buf.append ((String) elem);
+      }
+      else if (elem instanceof Expression) {
+	Object val = 
+	  ((Expression) elem).evaluate (pContext,
+					pResolver,
+					functions,
+					defaultPrefix,
+					pLogger);
+	if (val != null) {
+	  buf.append (val.toString ());
+	}
+      }
+    }
+    return buf.toString ();
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Returns the expression in the expression language syntax
+   **/
+  public String getExpressionString ()
+  {
+    StringBuffer buf = new StringBuffer ();
+    for (int i = 0; i < mElements.length; i++) {
+      Object elem = mElements [i];
+      if (elem instanceof String) {
+	buf.append ((String) elem);
+      }
+      else if (elem instanceof Expression) {
+	buf.append ("${");
+	buf.append (((Expression) elem).getExpressionString ());
+	buf.append ("}");
+      }
+    }
+    return buf.toString ();
+  }
+
+  //-------------------------------------
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/FloatingPointLiteral.java b/standard/src/org/apache/taglibs/standard/lang/jstl/FloatingPointLiteral.java
new file mode 100644
index 0000000..a3aaa97
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/FloatingPointLiteral.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl;
+
+/**
+ *
+ * <p>An expression representing a floating point literal value.  The
+ * value is stored internally as a double.
+ * 
+ * @author Nathan Abramson - Art Technology Group
+ * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: pierred $
+ **/
+
+public class FloatingPointLiteral
+  extends Literal
+{
+  //-------------------------------------
+  /**
+   *
+   * Constructor
+   **/
+  public FloatingPointLiteral (String pToken)
+  {
+    super (getValueFromToken (pToken));
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Parses the given token into the literal value
+   **/
+  static Object getValueFromToken (String pToken)
+  {
+    return new Double (pToken);
+  }
+
+  //-------------------------------------
+  // Expression methods
+  //-------------------------------------
+  /**
+   *
+   * Returns the expression in the expression language syntax
+   **/
+  public String getExpressionString ()
+  {
+    return getValue ().toString ();
+  }
+
+  //-------------------------------------
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/FunctionInvocation.java b/standard/src/org/apache/taglibs/standard/lang/jstl/FunctionInvocation.java
new file mode 100644
index 0000000..497a2e9
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/FunctionInvocation.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ *
+ * <p>Represents a function call.</p>
+ * 
+ * @author Shawn Bayern (in the style of Nathan's other classes)
+ **/
+
+public class FunctionInvocation
+  extends Expression
+{
+  //-------------------------------------
+  // Properties
+  //-------------------------------------
+  // property index
+
+  private String functionName;
+  private List argumentList;
+  public String getFunctionName() { return functionName; }
+  public void setFunctionName(String f) { functionName = f; }
+  public List getArgumentList() { return argumentList; }
+  public void setArgumentList(List l) { argumentList = l; }
+
+  //-------------------------------------
+  /**
+   * Constructor
+   **/
+  public FunctionInvocation (String functionName, List argumentList)
+  {
+    this.functionName = functionName;
+    this.argumentList = argumentList;
+  }
+
+  //-------------------------------------
+  // Expression methods
+  //-------------------------------------
+  /**
+   * Returns the expression in the expression language syntax
+   **/
+  public String getExpressionString ()
+  {
+    StringBuffer b = new StringBuffer();
+    b.append(functionName);
+    b.append("(");
+    Iterator i = argumentList.iterator();
+    while (i.hasNext()) {
+      b.append(((Expression) i.next()).getExpressionString());
+      if (i.hasNext())
+        b.append(", ");
+    }
+    b.append(")");
+    return b.toString();
+  }
+
+
+  //-------------------------------------
+  /**
+   *
+   * Evaluates by looking up the name in the VariableResolver
+   **/
+  public Object evaluate (Object pContext,
+                          VariableResolver pResolver,
+			  Map functions,
+			  String defaultPrefix,
+                          Logger pLogger)
+    throws ELException
+  {
+
+    // if the Map is null, then the function is invalid
+    if (functions == null)
+      pLogger.logError(Constants.UNKNOWN_FUNCTION, functionName);
+
+    // normalize function name against default prefix
+    String functionName = this.functionName;
+    if (functionName.indexOf(":") == -1) {
+      if (defaultPrefix == null)
+        pLogger.logError(Constants.UNKNOWN_FUNCTION, functionName);
+      functionName = defaultPrefix + ":" + functionName;
+    }
+
+    // ensure that the function's name is mapped
+    Method target = (Method) functions.get(functionName);
+    if (target == null)
+      pLogger.logError(Constants.UNKNOWN_FUNCTION, functionName);
+
+    // ensure that the number of arguments matches the number of parameters
+    Class[] params = target.getParameterTypes();
+    if (params.length != argumentList.size())
+      pLogger.logError(Constants.INAPPROPRIATE_FUNCTION_ARG_COUNT,
+		       new Integer(params.length),
+		       new Integer(argumentList.size()));
+
+    // now, walk through each parameter, evaluating and casting its argument
+    Object[] arguments = new Object[argumentList.size()];
+    for (int i = 0; i < params.length; i++) {
+      // evaluate
+      arguments[i] = ((Expression) argumentList.get(i)).evaluate(pContext,
+								 pResolver,
+								 functions,
+								 defaultPrefix,
+								 pLogger);
+      // coerce
+      arguments[i] = Coercions.coerce(arguments[i], params[i], pLogger);
+    }
+
+    // finally, invoke the target method, which we know to be static
+    try {
+      return (target.invoke(null, arguments));
+    } catch (InvocationTargetException ex) {
+      pLogger.logError(Constants.FUNCTION_INVOCATION_ERROR,
+			ex.getTargetException(),
+			functionName);
+      return null;
+    } catch (Exception ex) {
+      pLogger.logError(Constants.FUNCTION_INVOCATION_ERROR, ex, functionName);
+      return null;
+    }
+  }
+
+  //-------------------------------------
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/GreaterThanOperator.java b/standard/src/org/apache/taglibs/standard/lang/jstl/GreaterThanOperator.java
new file mode 100644
index 0000000..32799bc
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/GreaterThanOperator.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl;
+
+/**
+ *
+ * <p>The implementation of the greater than operator
+ * 
+ * @author Nathan Abramson - Art Technology Group
+ * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: pierred $
+ **/
+
+public class GreaterThanOperator
+  extends RelationalOperator
+{
+  //-------------------------------------
+  // Singleton
+  //-------------------------------------
+
+  public static final GreaterThanOperator SINGLETON =
+    new GreaterThanOperator ();
+
+  //-------------------------------------
+  /**
+   *
+   * Constructor
+   **/
+  public GreaterThanOperator ()
+  {
+  }
+
+  //-------------------------------------
+  // Expression methods
+  //-------------------------------------
+  /**
+   *
+   * Returns the symbol representing the operator
+   **/
+  public String getOperatorSymbol ()
+  {
+    return ">";
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Applies the operator to the given value
+   **/
+  public Object apply (Object pLeft,
+		       Object pRight,
+		       Object pContext,
+		       Logger pLogger)
+    throws ELException
+  {
+    if (pLeft == pRight) {
+      return Boolean.FALSE;
+    }
+    else if (pLeft == null ||
+	     pRight == null) {
+      return Boolean.FALSE;
+    }
+    else {
+      return super.apply (pLeft, pRight, pContext, pLogger);
+    }
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Applies the operator to the given double values
+   **/
+  public boolean apply (double pLeft,
+			double pRight,
+			Logger pLogger)
+  {
+    return pLeft > pRight;
+  }
+  
+  //-------------------------------------
+  /**
+   *
+   * Applies the operator to the given long values
+   **/
+  public boolean apply (long pLeft,
+			long pRight,
+			Logger pLogger)
+  {
+    return pLeft > pRight;
+  }
+  
+  //-------------------------------------
+  /**
+   *
+   * Applies the operator to the given String values
+   **/
+  public boolean apply (String pLeft,
+			String pRight,
+			Logger pLogger)
+  {
+    return pLeft.compareTo (pRight) > 0;
+  }
+
+  //-------------------------------------
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/GreaterThanOrEqualsOperator.java b/standard/src/org/apache/taglibs/standard/lang/jstl/GreaterThanOrEqualsOperator.java
new file mode 100644
index 0000000..792eec1
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/GreaterThanOrEqualsOperator.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl;
+
+/**
+ *
+ * <p>The implementation of the greater than or equals operator
+ * 
+ * @author Nathan Abramson - Art Technology Group
+ * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: pierred $
+ **/
+
+public class GreaterThanOrEqualsOperator
+  extends RelationalOperator
+{
+  //-------------------------------------
+  // Singleton
+  //-------------------------------------
+
+  public static final GreaterThanOrEqualsOperator SINGLETON =
+    new GreaterThanOrEqualsOperator ();
+
+  //-------------------------------------
+  /**
+   *
+   * Constructor
+   **/
+  public GreaterThanOrEqualsOperator ()
+  {
+  }
+
+  //-------------------------------------
+  // Expression methods
+  //-------------------------------------
+  /**
+   *
+   * Returns the symbol representing the operator
+   **/
+  public String getOperatorSymbol ()
+  {
+    return ">=";
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Applies the operator to the given value
+   **/
+  public Object apply (Object pLeft,
+		       Object pRight,
+		       Object pContext,
+		       Logger pLogger)
+    throws ELException
+  {
+    if (pLeft == pRight) {
+      return Boolean.TRUE;
+    }
+    else if (pLeft == null ||
+	     pRight == null) {
+      return Boolean.FALSE;
+    }
+    else {
+      return super.apply (pLeft, pRight, pContext, pLogger);
+    }
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Applies the operator to the given double values
+   **/
+  public boolean apply (double pLeft,
+			double pRight,
+			Logger pLogger)
+  {
+    return pLeft >= pRight;
+  }
+  
+  //-------------------------------------
+  /**
+   *
+   * Applies the operator to the given long values
+   **/
+  public boolean apply (long pLeft,
+			long pRight,
+			Logger pLogger)
+  {
+    return pLeft >= pRight;
+  }
+  
+  //-------------------------------------
+  /**
+   *
+   * Applies the operator to the given String values
+   **/
+  public boolean apply (String pLeft,
+			String pRight,
+			Logger pLogger)
+  {
+    return pLeft.compareTo (pRight) >= 0;
+  }
+
+  //-------------------------------------
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/ImplicitObjects.java b/standard/src/org/apache/taglibs/standard/lang/jstl/ImplicitObjects.java
new file mode 100644
index 0000000..4cedd7d
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/ImplicitObjects.java
@@ -0,0 +1,1142 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl;
+
+
+
+import java.util.ArrayList;
+
+import java.util.Collections;
+
+import java.util.Date;
+
+import java.util.Enumeration;
+
+import java.util.HashMap;
+
+import java.util.List;
+
+import java.util.Map;
+
+import javax.servlet.ServletContext;
+
+import javax.servlet.http.Cookie;
+
+import javax.servlet.http.HttpServletRequest;
+
+import javax.servlet.jsp.PageContext;
+
+
+
+/**
+
+ *
+
+ * <p>This class is used to generate the implicit Map and List objects
+
+ * that wrap various elements of the PageContext.  It also returns the
+
+ * correct implicit object for a given implicit object name.
+
+ * 
+
+ * @author Nathan Abramson - Art Technology Group
+
+ * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: horwat $
+
+ **/
+
+
+
+public class ImplicitObjects
+
+{
+
+  //-------------------------------------
+
+  // Constants
+
+  //-------------------------------------
+
+
+
+  static final String sAttributeName = 
+
+    "org.apache.taglibs.standard.ImplicitObjects";
+
+
+
+  //-------------------------------------
+
+  // Member variables
+
+  //-------------------------------------
+
+
+
+  PageContext mContext;
+
+  Map mPage;
+
+  Map mRequest;
+
+  Map mSession;
+
+  Map mApplication;
+
+  Map mParam;
+
+  Map mParams;
+
+  Map mHeader;
+
+  Map mHeaders;
+
+  Map mInitParam;
+
+  Map mCookie;
+
+
+
+  //-------------------------------------
+
+  /**
+
+   *
+
+   * Constructor
+
+   **/
+
+  public ImplicitObjects (PageContext pContext)
+
+  {
+
+    mContext = pContext;
+
+  }
+
+
+
+  //-------------------------------------
+
+  /**
+
+   *
+
+   * Finds the ImplicitObjects associated with the PageContext,
+
+   * creating it if it doesn't yet exist.
+
+   **/
+
+  public static ImplicitObjects getImplicitObjects (PageContext pContext)
+
+  {
+
+    ImplicitObjects objs = 
+
+      (ImplicitObjects)
+
+      pContext.getAttribute (sAttributeName,
+
+			     PageContext.PAGE_SCOPE);
+
+    if (objs == null) {
+
+      objs = new ImplicitObjects (pContext);
+
+      pContext.setAttribute (sAttributeName,
+
+			     objs,
+
+			     PageContext.PAGE_SCOPE);
+
+    }
+
+    return objs;
+
+  }
+
+
+
+  //-------------------------------------
+
+  /**
+
+   *
+
+   * Returns the Map that "wraps" page-scoped attributes
+
+   **/
+
+  public Map getPageScopeMap ()
+
+  {
+
+    if (mPage == null) {
+
+      mPage = createPageScopeMap (mContext);
+
+    }
+
+    return mPage;
+
+  }
+
+
+
+  //-------------------------------------
+
+  /**
+
+   *
+
+   * Returns the Map that "wraps" request-scoped attributes
+
+   **/
+
+  public Map getRequestScopeMap ()
+
+  {
+
+    if (mRequest == null) {
+
+      mRequest = createRequestScopeMap (mContext);
+
+    }
+
+    return mRequest;
+
+  }
+
+
+
+  //-------------------------------------
+
+  /**
+
+   *
+
+   * Returns the Map that "wraps" session-scoped attributes
+
+   **/
+
+  public Map getSessionScopeMap ()
+
+  {
+
+    if (mSession == null) {
+
+      mSession = createSessionScopeMap (mContext);
+
+    }
+
+    return mSession;
+
+  }
+
+
+
+  //-------------------------------------
+
+  /**
+
+   *
+
+   * Returns the Map that "wraps" application-scoped attributes
+
+   **/
+
+  public Map getApplicationScopeMap ()
+
+  {
+
+    if (mApplication == null) {
+
+      mApplication = createApplicationScopeMap (mContext);
+
+    }
+
+    return mApplication;
+
+  }
+
+
+
+  //-------------------------------------
+
+  /**
+
+   *
+
+   * Returns the Map that maps parameter name to a single parameter
+
+   * values.
+
+   **/
+
+  public Map getParamMap ()
+
+  {
+
+    if (mParam == null) {
+
+      mParam = createParamMap (mContext);
+
+    }
+
+    return mParam;
+
+  }
+
+
+
+  //-------------------------------------
+
+  /**
+
+   *
+
+   * Returns the Map that maps parameter name to an array of parameter
+
+   * values.
+
+   **/
+
+  public Map getParamsMap ()
+
+  {
+
+    if (mParams == null) {
+
+      mParams = createParamsMap (mContext);
+
+    }
+
+    return mParams;
+
+  }
+
+
+
+  //-------------------------------------
+
+  /**
+
+   *
+
+   * Returns the Map that maps header name to a single header
+
+   * values.
+
+   **/
+
+  public Map getHeaderMap ()
+
+  {
+
+    if (mHeader == null) {
+
+      mHeader = createHeaderMap (mContext);
+
+    }
+
+    return mHeader;
+
+  }
+
+
+
+  //-------------------------------------
+
+  /**
+
+   *
+
+   * Returns the Map that maps header name to an array of header
+
+   * values.
+
+   **/
+
+  public Map getHeadersMap ()
+
+  {
+
+    if (mHeaders == null) {
+
+      mHeaders = createHeadersMap (mContext);
+
+    }
+
+    return mHeaders;
+
+  }
+
+
+
+  //-------------------------------------
+
+  /**
+
+   *
+
+   * Returns the Map that maps init parameter name to a single init
+
+   * parameter values.
+
+   **/
+
+  public Map getInitParamMap ()
+
+  {
+
+    if (mInitParam == null) {
+
+      mInitParam = createInitParamMap (mContext);
+
+    }
+
+    return mInitParam;
+
+  }
+
+
+
+  //-------------------------------------
+
+  /**
+
+   *
+
+   * Returns the Map that maps cookie name to the first matching
+
+   * Cookie in request.getCookies().
+
+   **/
+
+  public Map getCookieMap ()
+
+  {
+
+    if (mCookie == null) {
+
+      mCookie = createCookieMap (mContext);
+
+    }
+
+    return mCookie;
+
+  }
+
+
+
+  //-------------------------------------
+
+  // Methods for generating wrapper maps
+
+  //-------------------------------------
+
+  /**
+
+   *
+
+   * Creates the Map that "wraps" page-scoped attributes
+
+   **/
+
+  public static Map createPageScopeMap (PageContext pContext)
+
+  {
+
+    final PageContext context = pContext;
+
+    return new EnumeratedMap ()
+
+      {
+
+	public Enumeration enumerateKeys () 
+
+	{
+
+	  return context.getAttributeNamesInScope
+
+	    (PageContext.PAGE_SCOPE);
+
+	}
+
+
+
+	public Object getValue (Object pKey) 
+
+	{
+
+	  if (pKey instanceof String) {
+
+	    return context.getAttribute
+
+	      ((String) pKey, 
+
+	       PageContext.PAGE_SCOPE);
+
+	  }
+
+	  else {
+
+	    return null;
+
+	  }
+
+	}
+
+
+
+	public boolean isMutable ()
+
+	{
+
+	  return true;
+
+	}
+
+      };
+
+  }
+
+
+
+  //-------------------------------------
+
+  /**
+
+   *
+
+   * Creates the Map that "wraps" request-scoped attributes
+
+   **/
+
+  public static Map createRequestScopeMap (PageContext pContext)
+
+  {
+
+    final PageContext context = pContext;
+
+    return new EnumeratedMap ()
+
+      {
+
+	public Enumeration enumerateKeys () 
+
+	{
+
+	  return context.getAttributeNamesInScope
+
+	    (PageContext.REQUEST_SCOPE);
+
+	}
+
+
+
+	public Object getValue (Object pKey) 
+
+	{
+
+	  if (pKey instanceof String) {
+
+	    return context.getAttribute
+
+	      ((String) pKey, 
+
+	       PageContext.REQUEST_SCOPE);
+
+	  }
+
+	  else {
+
+	    return null;
+
+	  }
+
+	}
+
+
+
+	public boolean isMutable ()
+
+	{
+
+	  return true;
+
+	}
+
+      };
+
+  }
+
+
+
+  //-------------------------------------
+
+  /**
+
+   *
+
+   * Creates the Map that "wraps" session-scoped attributes
+
+   **/
+
+  public static Map createSessionScopeMap (PageContext pContext)
+
+  {
+
+    final PageContext context = pContext;
+
+    return new EnumeratedMap ()
+
+      {
+
+	public Enumeration enumerateKeys () 
+
+	{
+
+	  return context.getAttributeNamesInScope
+
+	    (PageContext.SESSION_SCOPE);
+
+	}
+
+
+
+	public Object getValue (Object pKey) 
+
+	{
+
+	  if (pKey instanceof String) {
+
+	    return context.getAttribute
+
+	      ((String) pKey, 
+
+	       PageContext.SESSION_SCOPE);
+
+	  }
+
+	  else {
+
+	    return null;
+
+	  }
+
+	}
+
+
+
+	public boolean isMutable ()
+
+	{
+
+	  return true;
+
+	}
+
+      };
+
+  }
+
+
+
+  //-------------------------------------
+
+  /**
+
+   *
+
+   * Creates the Map that "wraps" application-scoped attributes
+
+   **/
+
+  public static Map createApplicationScopeMap (PageContext pContext)
+
+  {
+
+    final PageContext context = pContext;
+
+    return new EnumeratedMap ()
+
+      {
+
+	public Enumeration enumerateKeys () 
+
+	{
+
+	  return context.getAttributeNamesInScope
+
+	    (PageContext.APPLICATION_SCOPE);
+
+	}
+
+
+
+	public Object getValue (Object pKey) 
+
+	{
+
+	  if (pKey instanceof String) {
+
+	    return context.getAttribute
+
+	      ((String) pKey, 
+
+	       PageContext.APPLICATION_SCOPE);
+
+	  }
+
+	  else {
+
+	    return null;
+
+	  }
+
+	}
+
+
+
+	public boolean isMutable ()
+
+	{
+
+	  return true;
+
+	}
+
+      };
+
+  }
+
+
+
+  //-------------------------------------
+
+  /**
+
+   *
+
+   * Creates the Map that maps parameter name to single parameter
+
+   * value.
+
+   **/
+
+  public static Map createParamMap (PageContext pContext)
+
+  {
+
+    final HttpServletRequest request =
+
+      (HttpServletRequest) pContext.getRequest ();
+
+    return new EnumeratedMap ()
+
+      {
+
+	public Enumeration enumerateKeys () 
+
+	{
+
+	  return request.getParameterNames ();
+
+	}
+
+
+
+	public Object getValue (Object pKey) 
+
+	{
+
+	  if (pKey instanceof String) {
+
+	    return request.getParameter ((String) pKey);
+
+	  }
+
+	  else {
+
+	    return null;
+
+	  }
+
+	}
+
+
+
+	public boolean isMutable ()
+
+	{
+
+	  return false;
+
+	}
+
+      };
+
+  }
+
+
+
+  //-------------------------------------
+
+  /**
+
+   *
+
+   * Creates the Map that maps parameter name to an array of parameter
+
+   * values.
+
+   **/
+
+  public static Map createParamsMap (PageContext pContext)
+
+  {
+
+    final HttpServletRequest request =
+
+      (HttpServletRequest) pContext.getRequest ();
+
+    return new EnumeratedMap ()
+
+      {
+
+	public Enumeration enumerateKeys () 
+
+	{
+
+	  return request.getParameterNames ();
+
+	}
+
+
+
+	public Object getValue (Object pKey) 
+
+	{
+
+	  if (pKey instanceof String) {
+
+	    return request.getParameterValues ((String) pKey);
+
+	  }
+
+	  else {
+
+	    return null;
+
+	  }
+
+	}
+
+
+
+	public boolean isMutable ()
+
+	{
+
+	  return false;
+
+	}
+
+      };
+
+  }
+
+
+
+  //-------------------------------------
+
+  /**
+
+   *
+
+   * Creates the Map that maps header name to single header
+
+   * value.
+
+   **/
+
+  public static Map createHeaderMap (PageContext pContext)
+
+  {
+
+    final HttpServletRequest request =
+
+      (HttpServletRequest) pContext.getRequest ();
+
+    return new EnumeratedMap ()
+
+      {
+
+	public Enumeration enumerateKeys () 
+
+	{
+
+	  return request.getHeaderNames ();
+
+	}
+
+
+
+	public Object getValue (Object pKey) 
+
+	{
+
+	  if (pKey instanceof String) {
+
+	    return request.getHeader ((String) pKey);
+
+	  }
+
+	  else {
+
+	    return null;
+
+	  }
+
+	}
+
+
+
+	public boolean isMutable ()
+
+	{
+
+	  return false;
+
+	}
+
+      };
+
+  }
+
+
+
+  //-------------------------------------
+
+  /**
+
+   *
+
+   * Creates the Map that maps header name to an array of header
+
+   * values.
+
+   **/
+
+  public static Map createHeadersMap (PageContext pContext)
+
+  {
+
+    final HttpServletRequest request =
+
+      (HttpServletRequest) pContext.getRequest ();
+
+    return new EnumeratedMap ()
+
+      {
+
+	public Enumeration enumerateKeys () 
+
+	{
+
+	  return request.getHeaderNames ();
+
+	}
+
+
+
+	public Object getValue (Object pKey) 
+
+	{
+
+	  if (pKey instanceof String) {
+
+	    // Drain the header enumeration
+
+	    List l = new ArrayList ();
+
+	    Enumeration enum_ = request.getHeaders ((String) pKey);
+
+	    if (enum_ != null) {
+
+	      while (enum_.hasMoreElements ()) {
+
+		l.add (enum_.nextElement ());
+
+	      }
+
+	    }
+
+	    String [] ret = (String []) l.toArray (new String [l.size ()]);
+
+	    return ret;
+
+	  }
+
+	  else {
+
+	    return null;
+
+	  }
+
+	}
+
+
+
+	public boolean isMutable ()
+
+	{
+
+	  return false;
+
+	}
+
+      };
+
+  }
+
+
+
+  //-------------------------------------
+
+  /**
+
+   *
+
+   * Creates the Map that maps init parameter name to single init
+
+   * parameter value.
+
+   **/
+
+  public static Map createInitParamMap (PageContext pContext)
+
+  {
+
+    final ServletContext context = pContext.getServletContext ();
+
+    return new EnumeratedMap ()
+
+      {
+
+	public Enumeration enumerateKeys () 
+
+	{
+
+	  return context.getInitParameterNames ();
+
+	}
+
+
+
+	public Object getValue (Object pKey) 
+
+	{
+
+	  if (pKey instanceof String) {
+
+	    return context.getInitParameter ((String) pKey);
+
+	  }
+
+	  else {
+
+	    return null;
+
+	  }
+
+	}
+
+
+
+	public boolean isMutable ()
+
+	{
+
+	  return false;
+
+	}
+
+      };
+
+  }
+
+
+
+  //-------------------------------------
+
+  /**
+
+   *
+
+   * Creates the Map that maps cookie name to the first matching
+
+   * Cookie in request.getCookies().
+
+   **/
+
+  public static Map createCookieMap (PageContext pContext)
+
+  {
+
+    // Read all the cookies and construct the entire map
+
+    HttpServletRequest request = (HttpServletRequest) pContext.getRequest ();
+
+    Cookie [] cookies = request.getCookies ();
+
+    Map ret = new HashMap ();
+
+    for (int i = 0; cookies != null && i < cookies.length; i++) {
+
+      Cookie cookie = cookies [i];
+
+      if (cookie != null) {
+
+	String name = cookie.getName ();
+
+	if (!ret.containsKey (name)) {
+
+	  ret.put (name, cookie);
+
+	}
+
+      }
+
+    }
+
+    return ret;
+
+  }
+
+
+
+  //-------------------------------------
+
+}
+
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/IntegerDivideOperator.java b/standard/src/org/apache/taglibs/standard/lang/jstl/IntegerDivideOperator.java
new file mode 100644
index 0000000..7f0a096
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/IntegerDivideOperator.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl;
+
+/**
+ *
+ * <p>The implementation of the integer divide operator
+ * 
+ * @author Nathan Abramson - Art Technology Group
+ * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: pierred $
+ **/
+
+public class IntegerDivideOperator
+  extends BinaryOperator
+{
+  //-------------------------------------
+  // Singleton
+  //-------------------------------------
+
+  public static final IntegerDivideOperator SINGLETON =
+    new IntegerDivideOperator ();
+
+  //-------------------------------------
+  /**
+   *
+   * Constructor
+   **/
+  public IntegerDivideOperator ()
+  {
+  }
+
+  //-------------------------------------
+  // Expression methods
+  //-------------------------------------
+  /**
+   *
+   * Returns the symbol representing the operator
+   **/
+  public String getOperatorSymbol ()
+  {
+    return "idiv";
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Applies the operator to the given value
+   **/
+  public Object apply (Object pLeft,
+		       Object pRight,
+		       Object pContext,
+		       Logger pLogger)
+    throws ELException
+  {
+    if (pLeft == null &&
+	pRight == null) {
+      if (pLogger.isLoggingWarning ()) {
+	pLogger.logWarning
+	  (Constants.ARITH_OP_NULL,
+	   getOperatorSymbol ());
+      }
+      return PrimitiveObjects.getInteger (0);
+    }
+
+    long left =
+      Coercions.coerceToPrimitiveNumber (pLeft, Long.class, pLogger).
+      longValue ();
+    long right =
+      Coercions.coerceToPrimitiveNumber (pRight, Long.class, pLogger).
+      longValue ();
+
+    try {
+      return PrimitiveObjects.getLong (left / right);
+    }
+    catch (Exception exc) {
+      if (pLogger.isLoggingError ()) {
+	pLogger.logError
+	  (Constants.ARITH_ERROR,
+	   getOperatorSymbol (),
+	   "" + left,
+	   "" + right);
+      }
+      return PrimitiveObjects.getInteger (0);
+    }
+  }
+
+  //-------------------------------------
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/IntegerLiteral.java b/standard/src/org/apache/taglibs/standard/lang/jstl/IntegerLiteral.java
new file mode 100644
index 0000000..61b3327
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/IntegerLiteral.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl;
+
+/**
+ *
+ * <p>An expression representing an integer literal value.  The value
+ * is stored internally as a long.
+ * 
+ * @author Nathan Abramson - Art Technology Group
+ * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: pierred $
+ **/
+
+public class IntegerLiteral
+  extends Literal
+{
+  //-------------------------------------
+  /**
+   *
+   * Constructor
+   **/
+  public IntegerLiteral (String pToken)
+  {
+    super (getValueFromToken (pToken));
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Parses the given token into the literal value
+   **/
+  static Object getValueFromToken (String pToken)
+  {
+    return new Long (pToken);
+  }
+
+  //-------------------------------------
+  // Expression methods
+  //-------------------------------------
+  /**
+   *
+   * Returns the expression in the expression language syntax
+   **/
+  public String getExpressionString ()
+  {
+    return getValue ().toString ();
+  }
+
+  //-------------------------------------
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/JSTLVariableResolver.java b/standard/src/org/apache/taglibs/standard/lang/jstl/JSTLVariableResolver.java
new file mode 100644
index 0000000..a58c159
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/JSTLVariableResolver.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl;
+
+import javax.servlet.jsp.PageContext;
+
+/**
+ *
+ * <p>This is the JSTL-specific implementation of VariableResolver.
+ * It looks up variable references in the PageContext, and also
+ * recognizes references to implicit objects.
+ * 
+ * @author Nathan Abramson - Art Technology Group
+ * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: pierred $
+ **/
+
+public class JSTLVariableResolver
+  implements VariableResolver
+{
+  //-------------------------------------
+  /**
+   *
+   * Resolves the specified variable within the given context.
+   * Returns null if the variable is not found.
+   **/
+  public Object resolveVariable (String pName,
+				 Object pContext)
+    throws ELException
+  {
+    PageContext ctx = (PageContext) pContext;
+
+    // Check for implicit objects
+    if ("pageContext".equals (pName)) {
+      return ctx;
+    }
+    else if ("pageScope".equals (pName)) {
+      return ImplicitObjects.
+	getImplicitObjects (ctx).
+	getPageScopeMap ();
+    }
+    else if ("requestScope".equals (pName)) {
+      return ImplicitObjects.
+	getImplicitObjects (ctx).
+	getRequestScopeMap ();
+    }
+    else if ("sessionScope".equals (pName)) {
+      return ImplicitObjects.
+	getImplicitObjects (ctx).
+	getSessionScopeMap ();
+    }
+    else if ("applicationScope".equals (pName)) {
+      return ImplicitObjects.
+	getImplicitObjects (ctx).
+	getApplicationScopeMap ();
+    }
+    else if ("param".equals (pName)) {
+      return ImplicitObjects.
+	getImplicitObjects (ctx).
+	getParamMap ();
+    }
+    else if ("paramValues".equals (pName)) {
+      return ImplicitObjects.
+	getImplicitObjects (ctx).
+	getParamsMap ();
+    }
+    else if ("header".equals (pName)) {
+      return ImplicitObjects.
+	getImplicitObjects (ctx).
+	getHeaderMap ();
+    }
+    else if ("headerValues".equals (pName)) {
+      return ImplicitObjects.
+	getImplicitObjects (ctx).
+	getHeadersMap ();
+    }
+    else if ("initParam".equals (pName)) {
+      return ImplicitObjects.
+	getImplicitObjects (ctx).
+	getInitParamMap ();
+    }
+    else if ("cookie".equals (pName)) {
+      return ImplicitObjects.
+	getImplicitObjects (ctx).
+	getCookieMap ();
+    }
+
+    // Otherwise, just look it up in the page context
+    else {
+      return ctx.findAttribute (pName);
+    }
+  }
+					
+  //-------------------------------------
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/LessThanOperator.java b/standard/src/org/apache/taglibs/standard/lang/jstl/LessThanOperator.java
new file mode 100644
index 0000000..a630032
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/LessThanOperator.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl;
+
+/**
+ *
+ * <p>The implementation of the less than operator
+ * 
+ * @author Nathan Abramson - Art Technology Group
+ * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: pierred $
+ **/
+
+public class LessThanOperator
+  extends RelationalOperator
+{
+  //-------------------------------------
+  // Singleton
+  //-------------------------------------
+
+  public static final LessThanOperator SINGLETON =
+    new LessThanOperator ();
+
+  //-------------------------------------
+  /**
+   *
+   * Constructor
+   **/
+  public LessThanOperator ()
+  {
+  }
+
+  //-------------------------------------
+  // Expression methods
+  //-------------------------------------
+  /**
+   *
+   * Returns the symbol representing the operator
+   **/
+  public String getOperatorSymbol ()
+  {
+    return "<";
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Applies the operator to the given value
+   **/
+  public Object apply (Object pLeft,
+		       Object pRight,
+		       Object pContext,
+		       Logger pLogger)
+    throws ELException
+  {
+    if (pLeft == pRight) {
+      return Boolean.FALSE;
+    }
+    else if (pLeft == null ||
+	     pRight == null) {
+      return Boolean.FALSE;
+    }
+    else {
+      return super.apply (pLeft, pRight, pContext, pLogger);
+    }
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Applies the operator to the given double values
+   **/
+  public boolean apply (double pLeft,
+			double pRight,
+			Logger pLogger)
+  {
+    return pLeft < pRight;
+  }
+  
+  //-------------------------------------
+  /**
+   *
+   * Applies the operator to the given long values
+   **/
+  public boolean apply (long pLeft,
+			long pRight,
+			Logger pLogger)
+  {
+    return pLeft < pRight;
+  }
+  
+  //-------------------------------------
+  /**
+   *
+   * Applies the operator to the given String values
+   **/
+  public boolean apply (String pLeft,
+			String pRight,
+			Logger pLogger)
+  {
+    return pLeft.compareTo (pRight) < 0;
+  }
+
+  //-------------------------------------
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/LessThanOrEqualsOperator.java b/standard/src/org/apache/taglibs/standard/lang/jstl/LessThanOrEqualsOperator.java
new file mode 100644
index 0000000..53e5f61
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/LessThanOrEqualsOperator.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl;
+
+/**
+ *
+ * <p>The implementation of the less than or equals operator
+ * 
+ * @author Nathan Abramson - Art Technology Group
+ * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: pierred $
+ **/
+
+public class LessThanOrEqualsOperator
+  extends RelationalOperator
+{
+  //-------------------------------------
+  // Singleton
+  //-------------------------------------
+
+  public static final LessThanOrEqualsOperator SINGLETON =
+    new LessThanOrEqualsOperator ();
+
+  //-------------------------------------
+  /**
+   *
+   * Constructor
+   **/
+  public LessThanOrEqualsOperator ()
+  {
+  }
+
+  //-------------------------------------
+  // Expression methods
+  //-------------------------------------
+  /**
+   *
+   * Returns the symbol representing the operator
+   **/
+  public String getOperatorSymbol ()
+  {
+    return "<=";
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Applies the operator to the given value
+   **/
+  public Object apply (Object pLeft,
+		       Object pRight,
+		       Object pContext,
+		       Logger pLogger)
+    throws ELException
+  {
+    if (pLeft == pRight) {
+      return Boolean.TRUE;
+    }
+    else if (pLeft == null ||
+	     pRight == null) {
+      return Boolean.FALSE;
+    }
+    else {
+      return super.apply (pLeft, pRight, pContext, pLogger);
+    }
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Applies the operator to the given double values
+   **/
+  public boolean apply (double pLeft,
+			double pRight,
+			Logger pLogger)
+  {
+    return pLeft <= pRight;
+  }
+  
+  //-------------------------------------
+  /**
+   *
+   * Applies the operator to the given long values
+   **/
+  public boolean apply (long pLeft,
+			long pRight,
+			Logger pLogger)
+  {
+    return pLeft <= pRight;
+  }
+  
+  //-------------------------------------
+  /**
+   *
+   * Applies the operator to the given String values
+   **/
+  public boolean apply (String pLeft,
+			String pRight,
+			Logger pLogger)
+  {
+    return pLeft.compareTo (pRight) <= 0;
+  }
+
+  //-------------------------------------
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/Literal.java b/standard/src/org/apache/taglibs/standard/lang/jstl/Literal.java
new file mode 100644
index 0000000..8dbb903
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/Literal.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl;
+
+import java.util.Map;
+
+/**
+ *
+ * <p>An expression representing a literal value
+ * 
+ * @author Nathan Abramson - Art Technology Group
+ * @author Shawn Bayern
+ * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: pierred $
+ **/
+
+public abstract class Literal
+  extends Expression
+{
+  //-------------------------------------
+  // Properties
+  //-------------------------------------
+  // property value
+
+  Object mValue;
+  public Object getValue ()
+  { return mValue; }
+  public void setValue (Object pValue)
+  { mValue = pValue; }
+
+  //-------------------------------------
+  /**
+   *
+   * Constructor
+   **/
+  public Literal (Object pValue)
+  {
+    mValue = pValue;
+  }
+
+  //-------------------------------------
+  // Expression methods
+  //-------------------------------------
+  /**
+   *
+   * Evaluates to the literal value
+   **/
+  public Object evaluate (Object pContext,
+			  VariableResolver pResolver,
+			  Map functions,
+			  String defaultPrefix,
+			  Logger pLogger)
+    throws ELException
+  {
+    return mValue;
+  }
+
+  //-------------------------------------
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/Logger.java b/standard/src/org/apache/taglibs/standard/lang/jstl/Logger.java
new file mode 100644
index 0000000..6052a0d
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/Logger.java
@@ -0,0 +1,776 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl;
+
+import java.io.PrintStream;
+import java.text.MessageFormat;
+
+/**
+ *
+ * <p>The evaluator may pass an instance of this class to operators
+ * and expressions during evaluation.  They should use this to log any
+ * warning or error messages that might come up.  This allows all of
+ * our logging policies to be concentrated in one class.
+ *
+ * <p>Errors are conditions that are severe enough to abort operation.
+ * Warnings are conditions through which the operation may continue,
+ * but which should be reported to the developer.
+ * 
+ * @author Nathan Abramson - Art Technology Group
+ * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: pierred $
+ **/
+
+public class Logger
+{
+  //-------------------------------------
+  // Member variables
+  //-------------------------------------
+
+  PrintStream mOut;
+
+  //-------------------------------------
+  /**
+   *
+   * Constructor
+   *
+   * @param pOut the PrintStream to which warnings should be printed
+   **/
+  public Logger (PrintStream pOut)
+  {
+    mOut = pOut;
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Returns true if the application should even bother to try logging
+   * a warning.
+   **/
+  public boolean isLoggingWarning ()
+  {
+    return false;
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Logs a warning
+   **/
+  public void logWarning (String pMessage,
+			  Throwable pRootCause)
+    throws ELException
+  {
+    if (isLoggingWarning ()) {
+      if (pMessage == null) {
+	System.out.println (pRootCause);
+      }
+      else if (pRootCause == null) {
+	System.out.println (pMessage);
+      }
+      else {
+	System.out.println (pMessage + ": " + pRootCause);
+      }
+    }
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Logs a warning
+   **/
+  public void logWarning (String pTemplate)
+    throws ELException
+  {
+    if (isLoggingWarning ()) {
+      logWarning (pTemplate, null);
+    }
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Logs a warning
+   **/
+  public void logWarning (Throwable pRootCause)
+    throws ELException
+  {
+    if (isLoggingWarning ()) {
+      logWarning (null, pRootCause);
+    }
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Logs a warning
+   **/
+  public void logWarning (String pTemplate,
+			  Object pArg0)
+    throws ELException
+  {
+    if (isLoggingWarning ()) {
+      logWarning
+	(MessageFormat.format
+	 (pTemplate,
+	  new Object [] {
+	    "" + pArg0,
+	  }));
+    }
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Logs a warning
+   **/
+  public void logWarning (String pTemplate,
+			  Throwable pRootCause,
+			  Object pArg0)
+    throws ELException
+  {
+    if (isLoggingWarning ()) {
+      logWarning
+	(MessageFormat.format
+	 (pTemplate,
+	  new Object [] {
+	    "" + pArg0,
+	  }),
+	 pRootCause);
+    }
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Logs a warning
+   **/
+  public void logWarning (String pTemplate,
+			  Object pArg0,
+			  Object pArg1)
+    throws ELException
+  {
+    if (isLoggingWarning ()) {
+      logWarning
+	(MessageFormat.format
+	 (pTemplate,
+	  new Object [] {
+	    "" + pArg0,
+	    "" + pArg1,
+	  }));
+    }
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Logs a warning
+   **/
+  public void logWarning (String pTemplate,
+			  Throwable pRootCause,
+			  Object pArg0,
+			  Object pArg1)
+    throws ELException
+  {
+    if (isLoggingWarning ()) {
+      logWarning
+	(MessageFormat.format
+	 (pTemplate,
+	  new Object [] {
+	    "" + pArg0,
+	    "" + pArg1,
+	  }),
+	 pRootCause);
+    }
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Logs a warning
+   **/
+  public void logWarning (String pTemplate,
+			  Object pArg0,
+			  Object pArg1,
+			  Object pArg2)
+    throws ELException
+  {
+    if (isLoggingWarning ()) {
+      logWarning
+	(MessageFormat.format
+	 (pTemplate,
+	  new Object [] {
+	    "" + pArg0,
+	    "" + pArg1,
+	    "" + pArg2,
+	  }));
+    }
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Logs a warning
+   **/
+  public void logWarning (String pTemplate,
+			  Throwable pRootCause,
+			  Object pArg0,
+			  Object pArg1,
+			  Object pArg2)
+    throws ELException
+  {
+    if (isLoggingWarning ()) {
+      logWarning
+	(MessageFormat.format
+	 (pTemplate,
+	  new Object [] {
+	    "" + pArg0,
+	    "" + pArg1,
+	    "" + pArg2,
+	  }),
+	 pRootCause);
+    }
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Logs a warning
+   **/
+  public void logWarning (String pTemplate,
+			  Object pArg0,
+			  Object pArg1,
+			  Object pArg2,
+			  Object pArg3)
+    throws ELException
+  {
+    if (isLoggingWarning ()) {
+      logWarning
+	(MessageFormat.format
+	 (pTemplate,
+	  new Object [] {
+	    "" + pArg0,
+	    "" + pArg1,
+	    "" + pArg2,
+	    "" + pArg3,
+	  }));
+    }
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Logs a warning
+   **/
+  public void logWarning (String pTemplate,
+			  Throwable pRootCause,
+			  Object pArg0,
+			  Object pArg1,
+			  Object pArg2,
+			  Object pArg3)
+    throws ELException
+  {
+    if (isLoggingWarning ()) {
+      logWarning
+	(MessageFormat.format
+	 (pTemplate,
+	  new Object [] {
+	    "" + pArg0,
+	    "" + pArg1,
+	    "" + pArg2,
+	    "" + pArg3,
+	  }),
+	 pRootCause);
+    }
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Logs a warning
+   **/
+  public void logWarning (String pTemplate,
+			  Object pArg0,
+			  Object pArg1,
+			  Object pArg2,
+			  Object pArg3,
+			  Object pArg4)
+    throws ELException
+  {
+    if (isLoggingWarning ()) {
+      logWarning
+	(MessageFormat.format
+	 (pTemplate,
+	  new Object [] {
+	    "" + pArg0,
+	    "" + pArg1,
+	    "" + pArg2,
+	    "" + pArg3,
+	    "" + pArg4,
+	  }));
+    }
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Logs a warning
+   **/
+  public void logWarning (String pTemplate,
+			  Throwable pRootCause,
+			  Object pArg0,
+			  Object pArg1,
+			  Object pArg2,
+			  Object pArg3,
+			  Object pArg4)
+    throws ELException
+  {
+    if (isLoggingWarning ()) {
+      logWarning
+	(MessageFormat.format
+	 (pTemplate,
+	  new Object [] {
+	    "" + pArg0,
+	    "" + pArg1,
+	    "" + pArg2,
+	    "" + pArg3,
+	    "" + pArg4,
+	  }),
+	 pRootCause);
+    }
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Logs a warning
+   **/
+  public void logWarning (String pTemplate,
+			  Object pArg0,
+			  Object pArg1,
+			  Object pArg2,
+			  Object pArg3,
+			  Object pArg4,
+			  Object pArg5)
+    throws ELException
+  {
+    if (isLoggingWarning ()) {
+      logWarning
+	(MessageFormat.format
+	 (pTemplate,
+	  new Object [] {
+	    "" + pArg0,
+	    "" + pArg1,
+	    "" + pArg2,
+	    "" + pArg3,
+	    "" + pArg4,
+	    "" + pArg5,
+	  }));
+    }
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Logs a warning
+   **/
+  public void logWarning (String pTemplate,
+			  Throwable pRootCause,
+			  Object pArg0,
+			  Object pArg1,
+			  Object pArg2,
+			  Object pArg3,
+			  Object pArg4,
+			  Object pArg5)
+    throws ELException
+  {
+    if (isLoggingWarning ()) {
+      logWarning
+	(MessageFormat.format
+	 (pTemplate,
+	  new Object [] {
+	    "" + pArg0,
+	    "" + pArg1,
+	    "" + pArg2,
+	    "" + pArg3,
+	    "" + pArg4,
+	    "" + pArg5,
+	  }),
+	 pRootCause);
+    }
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Returns true if the application should even bother to try logging
+   * an error.
+   **/
+  public boolean isLoggingError ()
+  {
+    return true;
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Logs an error
+   **/
+  public void logError (String pMessage,
+			Throwable pRootCause)
+    throws ELException
+  {
+    if (isLoggingError ()) {
+      if (pMessage == null) {
+	throw new ELException (pRootCause);
+      }
+      else if (pRootCause == null) {
+	throw new ELException (pMessage);
+      }
+      else {
+	throw new ELException (pMessage, pRootCause);
+      }
+    }
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Logs an error
+   **/
+  public void logError (String pTemplate)
+    throws ELException
+  {
+    if (isLoggingError ()) {
+      logError (pTemplate, null);
+    }
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Logs an error
+   **/
+  public void logError (Throwable pRootCause)
+    throws ELException
+  {
+    if (isLoggingError ()) {
+      logError (null, pRootCause);
+    }
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Logs an error
+   **/
+  public void logError (String pTemplate,
+			Object pArg0)
+    throws ELException
+  {
+    if (isLoggingError ()) {
+      logError
+	(MessageFormat.format
+	 (pTemplate,
+	  new Object [] {
+	    "" + pArg0,
+	  }));
+    }
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Logs an error
+   **/
+  public void logError (String pTemplate,
+			Throwable pRootCause,
+			Object pArg0)
+    throws ELException
+  {
+    if (isLoggingError ()) {
+      logError
+	(MessageFormat.format
+	 (pTemplate,
+	  new Object [] {
+	    "" + pArg0,
+	  }),
+	 pRootCause);
+    }
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Logs an error
+   **/
+  public void logError (String pTemplate,
+			Object pArg0,
+			Object pArg1)
+    throws ELException
+  {
+    if (isLoggingError ()) {
+      logError
+	(MessageFormat.format
+	 (pTemplate,
+	  new Object [] {
+	    "" + pArg0,
+	    "" + pArg1,
+	  }));
+    }
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Logs an error
+   **/
+  public void logError (String pTemplate,
+			Throwable pRootCause,
+			Object pArg0,
+			Object pArg1)
+    throws ELException
+  {
+    if (isLoggingError ()) {
+      logError
+	(MessageFormat.format
+	 (pTemplate,
+	  new Object [] {
+	    "" + pArg0,
+	    "" + pArg1,
+	  }),
+	 pRootCause);
+    }
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Logs an error
+   **/
+  public void logError (String pTemplate,
+			Object pArg0,
+			Object pArg1,
+			Object pArg2)
+    throws ELException
+  {
+    if (isLoggingError ()) {
+      logError
+	(MessageFormat.format
+	 (pTemplate,
+	  new Object [] {
+	    "" + pArg0,
+	    "" + pArg1,
+	    "" + pArg2,
+	  }));
+    }
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Logs an error
+   **/
+  public void logError (String pTemplate,
+			Throwable pRootCause,
+			Object pArg0,
+			Object pArg1,
+			Object pArg2)
+    throws ELException
+  {
+    if (isLoggingError ()) {
+      logError
+	(MessageFormat.format
+	 (pTemplate,
+	  new Object [] {
+	    "" + pArg0,
+	    "" + pArg1,
+	    "" + pArg2,
+	  }),
+	 pRootCause);
+    }
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Logs an error
+   **/
+  public void logError (String pTemplate,
+			Object pArg0,
+			Object pArg1,
+			Object pArg2,
+			Object pArg3)
+    throws ELException
+  {
+    if (isLoggingError ()) {
+      logError
+	(MessageFormat.format
+	 (pTemplate,
+	  new Object [] {
+	    "" + pArg0,
+	    "" + pArg1,
+	    "" + pArg2,
+	    "" + pArg3,
+	  }));
+    }
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Logs an error
+   **/
+  public void logError (String pTemplate,
+			Throwable pRootCause,
+			Object pArg0,
+			Object pArg1,
+			Object pArg2,
+			Object pArg3)
+    throws ELException
+  {
+    if (isLoggingError ()) {
+      logError
+	(MessageFormat.format
+	 (pTemplate,
+	  new Object [] {
+	    "" + pArg0,
+	    "" + pArg1,
+	    "" + pArg2,
+	    "" + pArg3,
+	  }),
+	 pRootCause);
+    }
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Logs an error
+   **/
+  public void logError (String pTemplate,
+			Object pArg0,
+			Object pArg1,
+			Object pArg2,
+			Object pArg3,
+			Object pArg4)
+    throws ELException
+  {
+    if (isLoggingError ()) {
+      logError
+	(MessageFormat.format
+	 (pTemplate,
+	  new Object [] {
+	    "" + pArg0,
+	    "" + pArg1,
+	    "" + pArg2,
+	    "" + pArg3,
+	    "" + pArg4,
+	  }));
+    }
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Logs an error
+   **/
+  public void logError (String pTemplate,
+			Throwable pRootCause,
+			Object pArg0,
+			Object pArg1,
+			Object pArg2,
+			Object pArg3,
+			Object pArg4)
+    throws ELException
+  {
+    if (isLoggingError ()) {
+      logError
+	(MessageFormat.format
+	 (pTemplate,
+	  new Object [] {
+	    "" + pArg0,
+	    "" + pArg1,
+	    "" + pArg2,
+	    "" + pArg3,
+	    "" + pArg4,
+	  }),
+	 pRootCause);
+    }
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Logs an error
+   **/
+  public void logError (String pTemplate,
+			Object pArg0,
+			Object pArg1,
+			Object pArg2,
+			Object pArg3,
+			Object pArg4,
+			Object pArg5)
+    throws ELException
+  {
+    if (isLoggingError ()) {
+      logError
+	(MessageFormat.format
+	 (pTemplate,
+	  new Object [] {
+	    "" + pArg0,
+	    "" + pArg1,
+	    "" + pArg2,
+	    "" + pArg3,
+	    "" + pArg4,
+	    "" + pArg5,
+	  }));
+    }
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Logs an error
+   **/
+  public void logError (String pTemplate,
+			Throwable pRootCause,
+			Object pArg0,
+			Object pArg1,
+			Object pArg2,
+			Object pArg3,
+			Object pArg4,
+			Object pArg5)
+    throws ELException
+  {
+    if (isLoggingError ()) {
+      logError
+	(MessageFormat.format
+	 (pTemplate,
+	  new Object [] {
+	    "" + pArg0,
+	    "" + pArg1,
+	    "" + pArg2,
+	    "" + pArg3,
+	    "" + pArg4,
+	    "" + pArg5,
+	  }),
+	 pRootCause);
+    }
+  }
+
+  //-------------------------------------
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/MinusOperator.java b/standard/src/org/apache/taglibs/standard/lang/jstl/MinusOperator.java
new file mode 100644
index 0000000..3ee857a
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/MinusOperator.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl;
+
+/**
+ *
+ * <p>The implementation of the minus operator
+ * 
+ * @author Nathan Abramson - Art Technology Group
+ * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: pierred $
+ **/
+
+public class MinusOperator
+  extends ArithmeticOperator
+{
+  //-------------------------------------
+  // Singleton
+  //-------------------------------------
+
+  public static final MinusOperator SINGLETON =
+    new MinusOperator ();
+
+  //-------------------------------------
+  /**
+   *
+   * Constructor
+   **/
+  public MinusOperator ()
+  {
+  }
+
+  //-------------------------------------
+  // Expression methods
+  //-------------------------------------
+  /**
+   *
+   * Returns the symbol representing the operator
+   **/
+  public String getOperatorSymbol ()
+  {
+    return "-";
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Applies the operator to the given double values, returning a double
+   **/
+  public double apply (double pLeft,
+		       double pRight,
+		       Logger pLogger)
+  {
+    return pLeft - pRight;
+  }
+  
+  //-------------------------------------
+  /**
+   *
+   * Applies the operator to the given double values, returning a double
+   **/
+  public long apply (long pLeft,
+		     long pRight,
+		     Logger pLogger)
+  {
+    return pLeft - pRight;
+  }
+  
+  //-------------------------------------
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/ModulusOperator.java b/standard/src/org/apache/taglibs/standard/lang/jstl/ModulusOperator.java
new file mode 100644
index 0000000..be9ba53
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/ModulusOperator.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl;
+
+/**
+ *
+ * <p>The implementation of the modulus operator
+ * 
+ * @author Nathan Abramson - Art Technology Group
+ * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: pierred $
+ **/
+
+public class ModulusOperator
+  extends BinaryOperator
+{
+  //-------------------------------------
+  // Singleton
+  //-------------------------------------
+
+  public static final ModulusOperator SINGLETON =
+    new ModulusOperator ();
+
+  //-------------------------------------
+  /**
+   *
+   * Constructor
+   **/
+  public ModulusOperator ()
+  {
+  }
+
+  //-------------------------------------
+  // Expression methods
+  //-------------------------------------
+  /**
+   *
+   * Returns the symbol representing the operator
+   **/
+  public String getOperatorSymbol ()
+  {
+    return "%";
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Applies the operator to the given value
+   **/
+  public Object apply (Object pLeft,
+		       Object pRight,
+		       Object pContext,
+		       Logger pLogger)
+    throws ELException
+  {
+    if (pLeft == null &&
+	pRight == null) {
+      if (pLogger.isLoggingWarning ()) {
+	pLogger.logWarning
+	  (Constants.ARITH_OP_NULL,
+	   getOperatorSymbol ());
+      }
+      return PrimitiveObjects.getInteger (0);
+    }
+
+    if ((pLeft != null &&
+	 (Coercions.isFloatingPointType (pLeft) ||
+	  Coercions.isFloatingPointString (pLeft))) ||
+	(pRight != null &&
+	 (Coercions.isFloatingPointType (pRight) ||
+	  Coercions.isFloatingPointString (pRight)))) {
+      double left =
+	Coercions.coerceToPrimitiveNumber (pLeft, Double.class, pLogger).
+	doubleValue ();
+      double right =
+	Coercions.coerceToPrimitiveNumber (pRight, Double.class, pLogger).
+	doubleValue ();
+
+      try {
+	return PrimitiveObjects.getDouble (left % right);
+      }
+      catch (Exception exc) {
+	if (pLogger.isLoggingError ()) {
+	  pLogger.logError
+	    (Constants.ARITH_ERROR,
+	     getOperatorSymbol (),
+	     "" + left,
+	     "" + right);
+	}
+	return PrimitiveObjects.getInteger (0);
+      }
+    }
+    else {
+      long left =
+	Coercions.coerceToPrimitiveNumber (pLeft, Long.class, pLogger).
+	longValue ();
+      long right =
+	Coercions.coerceToPrimitiveNumber (pRight, Long.class, pLogger).
+	longValue ();
+
+      try {
+	return PrimitiveObjects.getLong (left % right);
+      }
+      catch (Exception exc) {
+	if (pLogger.isLoggingError ()) {
+	  pLogger.logError
+	    (Constants.ARITH_ERROR,
+	     getOperatorSymbol (),
+	     "" + left,
+	     "" + right);
+	}
+	return PrimitiveObjects.getInteger (0);
+      }
+    }
+  }
+
+  //-------------------------------------
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/MultiplyOperator.java b/standard/src/org/apache/taglibs/standard/lang/jstl/MultiplyOperator.java
new file mode 100644
index 0000000..5f45d3a
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/MultiplyOperator.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl;
+
+/**
+ *
+ * <p>The implementation of the multiply operator
+ * 
+ * @author Nathan Abramson - Art Technology Group
+ * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: pierred $
+ **/
+
+public class MultiplyOperator
+  extends ArithmeticOperator
+{
+  //-------------------------------------
+  // Singleton
+  //-------------------------------------
+
+  public static final MultiplyOperator SINGLETON =
+    new MultiplyOperator ();
+
+  //-------------------------------------
+  /**
+   *
+   * Constructor
+   **/
+  public MultiplyOperator ()
+  {
+  }
+
+  //-------------------------------------
+  // Expression methods
+  //-------------------------------------
+  /**
+   *
+   * Returns the symbol representing the operator
+   **/
+  public String getOperatorSymbol ()
+  {
+    return "*";
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Applies the operator to the given double values, returning a double
+   **/
+  public double apply (double pLeft,
+		       double pRight,
+		       Logger pLogger)
+  {
+    return pLeft * pRight;
+  }
+  
+  //-------------------------------------
+  /**
+   *
+   * Applies the operator to the given double values, returning a double
+   **/
+  public long apply (long pLeft,
+		     long pRight,
+		     Logger pLogger)
+  {
+    return pLeft * pRight;
+  }
+  
+  //-------------------------------------
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/NamedValue.java b/standard/src/org/apache/taglibs/standard/lang/jstl/NamedValue.java
new file mode 100644
index 0000000..2c3a665
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/NamedValue.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl;
+
+import java.util.Map;
+
+/**
+ *
+ * <p>Represents a name that can be used as the first element of a
+ * value.
+ * 
+ * @author Nathan Abramson - Art Technology Group
+ * @author Shawn Bayern
+ * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: pierred $
+ **/
+
+public class NamedValue
+  extends Expression
+{
+  //-------------------------------------
+  // Constants
+  //-------------------------------------
+
+  //-------------------------------------
+  // Properties
+  //-------------------------------------
+  // property name
+
+  String mName;
+  public String getName ()
+  { return mName; }
+
+  //-------------------------------------
+  /**
+   *
+   * Constructor
+   **/
+  public NamedValue (String pName)
+  {
+    mName = pName;
+  }
+
+  //-------------------------------------
+  // Expression methods
+  //-------------------------------------
+  /**
+   *
+   * Returns the expression in the expression language syntax
+   **/
+  public String getExpressionString ()
+  {
+    return StringLiteral.toIdentifierToken (mName);
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Evaluates by looking up the name in the VariableResolver
+   **/
+  public Object evaluate (Object pContext,
+			  VariableResolver pResolver,
+			  Map functions,
+			  String defaultPrefix,
+			  Logger pLogger)
+    throws ELException
+  {
+    if (pResolver == null) {
+      return null;
+    }
+    else {
+      return pResolver.resolveVariable (mName, pContext);
+    }
+  }
+
+  //-------------------------------------
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/NotEqualsOperator.java b/standard/src/org/apache/taglibs/standard/lang/jstl/NotEqualsOperator.java
new file mode 100644
index 0000000..71b774c
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/NotEqualsOperator.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl;
+
+/**
+ *
+ * <p>The implementation of the not equals operator
+ * 
+ * @author Nathan Abramson - Art Technology Group
+ * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: pierred $
+ **/
+
+public class NotEqualsOperator
+  extends EqualityOperator
+{
+  //-------------------------------------
+  // Singleton
+  //-------------------------------------
+
+  public static final NotEqualsOperator SINGLETON =
+    new NotEqualsOperator ();
+
+  //-------------------------------------
+  /**
+   *
+   * Constructor
+   **/
+  public NotEqualsOperator ()
+  {
+  }
+
+  //-------------------------------------
+  // Expression methods
+  //-------------------------------------
+  /**
+   *
+   * Returns the symbol representing the operator
+   **/
+  public String getOperatorSymbol ()
+  {
+    return "!=";
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Applies the operator given the fact that the two elements are
+   * equal.
+   **/
+  public boolean apply (boolean pAreEqual,
+			Logger pLogger)
+  {
+    return !pAreEqual;
+  }
+  
+  //-------------------------------------
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/NotOperator.java b/standard/src/org/apache/taglibs/standard/lang/jstl/NotOperator.java
new file mode 100644
index 0000000..072140b
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/NotOperator.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl;
+
+/**
+ *
+ * <p>The implementation of the not operator
+ * 
+ * @author Nathan Abramson - Art Technology Group
+ * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: pierred $
+ **/
+
+public class NotOperator
+  extends UnaryOperator
+{
+  //-------------------------------------
+  // Singleton
+  //-------------------------------------
+
+  public static final NotOperator SINGLETON =
+    new NotOperator ();
+
+  //-------------------------------------
+  /**
+   *
+   * Constructor
+   **/
+  public NotOperator ()
+  {
+  }
+
+  //-------------------------------------
+  // Expression methods
+  //-------------------------------------
+  /**
+   *
+   * Returns the symbol representing the operator
+   **/
+  public String getOperatorSymbol ()
+  {
+    return "not";
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Applies the operator to the given value
+   **/
+  public Object apply (Object pValue,
+		       Object pContext,
+		       Logger pLogger)
+    throws ELException
+  {
+    // Coerce the value to a boolean
+    boolean val = Coercions.coerceToBoolean (pValue, pLogger).booleanValue ();
+
+    return PrimitiveObjects.getBoolean (!val);
+  }
+
+  //-------------------------------------
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/NullLiteral.java b/standard/src/org/apache/taglibs/standard/lang/jstl/NullLiteral.java
new file mode 100644
index 0000000..d634713
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/NullLiteral.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl;
+
+/**
+ *
+ * <p>An expression representing a null literal value
+ * 
+ * @author Nathan Abramson - Art Technology Group
+ * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: pierred $
+ **/
+
+public class NullLiteral
+  extends Literal
+{
+  //-------------------------------------
+  // Member variables
+  //-------------------------------------
+
+  public static final NullLiteral SINGLETON = new NullLiteral ();
+
+  //-------------------------------------
+  /**
+   *
+   * Constructor
+   **/
+  public NullLiteral ()
+  {
+    super (null);
+  }
+
+  //-------------------------------------
+  // Expression methods
+  //-------------------------------------
+  /**
+   *
+   * Returns the expression in the expression language syntax
+   **/
+  public String getExpressionString ()
+  {
+    return "null";
+  }
+
+  //-------------------------------------
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/OrOperator.java b/standard/src/org/apache/taglibs/standard/lang/jstl/OrOperator.java
new file mode 100644
index 0000000..108afa0
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/OrOperator.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl;
+
+/**
+ *
+ * <p>The implementation of the or operator
+ * 
+ * @author Nathan Abramson - Art Technology Group
+ * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: pierred $
+ **/
+
+public class OrOperator
+  extends BinaryOperator
+{
+  //-------------------------------------
+  // Singleton
+  //-------------------------------------
+
+  public static final OrOperator SINGLETON =
+    new OrOperator ();
+
+  //-------------------------------------
+  /**
+   *
+   * Constructor
+   **/
+  public OrOperator ()
+  {
+  }
+
+  //-------------------------------------
+  // Expression methods
+  //-------------------------------------
+  /**
+   *
+   * Returns the symbol representing the operator
+   **/
+  public String getOperatorSymbol ()
+  {
+    return "or";
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Applies the operator to the given value
+   **/
+  public Object apply (Object pLeft,
+		       Object pRight,
+		       Object pContext,
+		       Logger pLogger)
+    throws ELException
+  {
+    // Coerce the values to booleans
+    boolean left = 
+      Coercions.coerceToBoolean (pLeft, pLogger).booleanValue ();
+    boolean right = 
+      Coercions.coerceToBoolean (pRight, pLogger).booleanValue ();
+
+    return PrimitiveObjects.getBoolean (left || right);
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Returns true if evaluation is necessary given the specified Left
+   * value.  The And/OrOperators make use of this
+   **/
+  public boolean shouldEvaluate (Object pLeft)
+  {
+    return
+      (pLeft instanceof Boolean) &&
+      ((Boolean) pLeft).booleanValue () == false;
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Returns true if the operator expects its arguments to be coerced
+   * to Booleans.  The And/Or operators set this to true.
+   **/
+  public boolean shouldCoerceToBoolean ()
+  {
+    return true;
+  }
+
+  //-------------------------------------
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/PlusOperator.java b/standard/src/org/apache/taglibs/standard/lang/jstl/PlusOperator.java
new file mode 100644
index 0000000..128e4f5
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/PlusOperator.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl;
+
+/**
+ *
+ * <p>The implementation of the plus operator
+ * 
+ * @author Nathan Abramson - Art Technology Group
+ * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: pierred $
+ **/
+
+public class PlusOperator
+  extends ArithmeticOperator
+{
+  //-------------------------------------
+  // Singleton
+  //-------------------------------------
+
+  public static final PlusOperator SINGLETON =
+    new PlusOperator ();
+
+  //-------------------------------------
+  /**
+   *
+   * Constructor
+   **/
+  public PlusOperator ()
+  {
+  }
+
+  //-------------------------------------
+  // Expression methods
+  //-------------------------------------
+  /**
+   *
+   * Returns the symbol representing the operator
+   **/
+  public String getOperatorSymbol ()
+  {
+    return "+";
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Applies the operator to the given double values, returning a double
+   **/
+  public double apply (double pLeft,
+		       double pRight,
+		       Logger pLogger)
+  {
+    return pLeft + pRight;
+  }
+  
+  //-------------------------------------
+  /**
+   *
+   * Applies the operator to the given double values, returning a double
+   **/
+  public long apply (long pLeft,
+		     long pRight,
+		     Logger pLogger)
+  {
+    return pLeft + pRight;
+  }
+  
+  //-------------------------------------
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/PrimitiveObjects.java b/standard/src/org/apache/taglibs/standard/lang/jstl/PrimitiveObjects.java
new file mode 100644
index 0000000..ecf46e3
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/PrimitiveObjects.java
@@ -0,0 +1,242 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl;
+
+/**
+ *
+ * <p>This converts primitive values to their Object counterparts.
+ * For bytes and chars, values from 0 to 255 are cached.  For shorts,
+ * ints, and longs, values -1000 to 1000 are cached.
+ * 
+ * @author Nathan Abramson - Art Technology Group
+ * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: pierred $
+ **/
+
+class PrimitiveObjects
+{
+  //-------------------------------------
+  // Constants
+  //-------------------------------------
+
+  static int BYTE_LOWER_BOUND = 0;
+  static int BYTE_UPPER_BOUND = 255;
+  static int CHARACTER_LOWER_BOUND = 0;
+  static int CHARACTER_UPPER_BOUND = 255;
+  static int SHORT_LOWER_BOUND = -1000;
+  static int SHORT_UPPER_BOUND = 1000;
+  static int INTEGER_LOWER_BOUND = -1000;
+  static int INTEGER_UPPER_BOUND = 1000;
+  static int LONG_LOWER_BOUND = -1000;
+  static int LONG_UPPER_BOUND = 1000;
+
+  //-------------------------------------
+  // Member variables
+  //-------------------------------------
+
+  static Byte [] mBytes = createBytes ();
+  static Character [] mCharacters = createCharacters ();
+  static Short [] mShorts = createShorts ();
+  static Integer [] mIntegers = createIntegers ();
+  static Long [] mLongs = createLongs ();
+
+  //-------------------------------------
+  // Getting primitive values
+  //-------------------------------------
+  public static Boolean getBoolean (boolean pValue)
+  {
+    return
+      pValue ?
+      Boolean.TRUE :
+      Boolean.FALSE;
+  }
+
+  //-------------------------------------
+  public static Byte getByte (byte pValue)
+  {
+    if (pValue >= BYTE_LOWER_BOUND &&
+	pValue <= BYTE_UPPER_BOUND) {
+      return mBytes [((int) pValue) - BYTE_LOWER_BOUND];
+    }
+    else {
+      return new Byte (pValue);
+    }
+  }
+
+  //-------------------------------------
+  public static Character getCharacter (char pValue)
+  {
+    if (pValue >= CHARACTER_LOWER_BOUND &&
+	pValue <= CHARACTER_UPPER_BOUND) {
+      return mCharacters [((int) pValue) - CHARACTER_LOWER_BOUND];
+    }
+    else {
+      return new Character (pValue);
+    }
+  }
+
+  //-------------------------------------
+  public static Short getShort (short pValue)
+  {
+    if (pValue >= SHORT_LOWER_BOUND &&
+	pValue <= SHORT_UPPER_BOUND) {
+      return mShorts [((int) pValue) - SHORT_LOWER_BOUND];
+    }
+    else {
+      return new Short (pValue);
+    }
+  }
+
+  //-------------------------------------
+  public static Integer getInteger (int pValue)
+  {
+    if (pValue >= INTEGER_LOWER_BOUND &&
+	pValue <= INTEGER_UPPER_BOUND) {
+      return mIntegers [((int) pValue) - INTEGER_LOWER_BOUND];
+    }
+    else {
+      return new Integer (pValue);
+    }
+  }
+
+  //-------------------------------------
+  public static Long getLong (long pValue)
+  {
+    if (pValue >= LONG_LOWER_BOUND &&
+	pValue <= LONG_UPPER_BOUND) {
+      return mLongs [((int) pValue) - LONG_LOWER_BOUND];
+    }
+    else {
+      return new Long (pValue);
+    }
+  }
+
+  //-------------------------------------
+  public static Float getFloat (float pValue)
+  {
+    return new Float (pValue);
+  }
+
+  //-------------------------------------
+  public static Double getDouble (double pValue)
+  {
+    return new Double (pValue);
+  }
+
+  //-------------------------------------
+  // Object class equivalents of primitive classes
+  //-------------------------------------
+  /**
+   *
+   * If the given class is a primitive class, returns the object
+   * version of that class.  Otherwise, the class is just returned.
+   **/
+  public static Class getPrimitiveObjectClass (Class pClass)
+  {
+    if (pClass == Boolean.TYPE) {
+      return Boolean.class;
+    }
+    else if (pClass == Byte.TYPE) {
+      return Byte.class;
+    }
+    else if (pClass == Short.TYPE) {
+      return Short.class;
+    }
+    else if (pClass == Character.TYPE) {
+      return Character.class;
+    }
+    else if (pClass == Integer.TYPE) {
+      return Integer.class;
+    }
+    else if (pClass == Long.TYPE) {
+      return Long.class;
+    }
+    else if (pClass == Float.TYPE) {
+      return Float.class;
+    }
+    else if (pClass == Double.TYPE) {
+      return Double.class;
+    }
+    else {
+      return pClass;
+    }
+  }
+
+  //-------------------------------------
+  // Initializing the cached values
+  //-------------------------------------
+  static Byte [] createBytes ()
+  {
+    int len = BYTE_UPPER_BOUND - BYTE_LOWER_BOUND + 1;
+    Byte [] ret = new Byte [len];
+    byte val = (byte) BYTE_LOWER_BOUND;
+    for (int i = 0; i < len; i++, val++) {
+      ret [i] = new Byte (val);
+    }
+    return ret;
+  }
+
+  //-------------------------------------
+  static Character [] createCharacters ()
+  {
+    int len = CHARACTER_UPPER_BOUND - CHARACTER_LOWER_BOUND + 1;
+    Character [] ret = new Character [len];
+    char val = (char) CHARACTER_LOWER_BOUND;
+    for (int i = 0; i < len; i++, val++) {
+      ret [i] = new Character (val);
+    }
+    return ret;
+  }
+
+  //-------------------------------------
+  static Short [] createShorts ()
+  {
+    int len = SHORT_UPPER_BOUND - SHORT_LOWER_BOUND + 1;
+    Short [] ret = new Short [len];
+    short val = (short) SHORT_LOWER_BOUND;
+    for (int i = 0; i < len; i++, val++) {
+      ret [i] = new Short (val);
+    }
+    return ret;
+  }
+
+  //-------------------------------------
+  static Integer [] createIntegers ()
+  {
+    int len = INTEGER_UPPER_BOUND - INTEGER_LOWER_BOUND + 1;
+    Integer [] ret = new Integer [len];
+    int val = (int) INTEGER_LOWER_BOUND;
+    for (int i = 0; i < len; i++, val++) {
+      ret [i] = new Integer (val);
+    }
+    return ret;
+  }
+
+  //-------------------------------------
+  static Long [] createLongs ()
+  {
+    int len = LONG_UPPER_BOUND - LONG_LOWER_BOUND + 1;
+    Long [] ret = new Long [len];
+    long val = (long) LONG_LOWER_BOUND;
+    for (int i = 0; i < len; i++, val++) {
+      ret [i] = new Long (val);
+    }
+    return ret;
+  }
+
+  //-------------------------------------
+
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/PropertySuffix.java b/standard/src/org/apache/taglibs/standard/lang/jstl/PropertySuffix.java
new file mode 100644
index 0000000..29be688
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/PropertySuffix.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl;
+
+import java.util.Map;
+
+/**
+ *
+ * <p>Represents an operator that obtains the value of another value's
+ * property.  This is a specialization of ArraySuffix - a.b is
+ * equivalent to a["b"]
+ * 
+ * @author Nathan Abramson - Art Technology Group
+ * @author Shawn Bayern
+ * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: pierred $
+ **/
+
+public class PropertySuffix
+  extends ArraySuffix
+{
+  //-------------------------------------
+  // Properties
+  //-------------------------------------
+  // property name
+
+  String mName;
+  public String getName ()
+  { return mName; }
+  public void setName (String pName)
+  { mName = pName; }
+
+  //-------------------------------------
+  /**
+   *
+   * Constructor
+   **/
+  public PropertySuffix (String pName)
+  {
+    super (null);
+    mName = pName;
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Gets the value of the index
+   **/
+  Object evaluateIndex (Object pContext,
+                        VariableResolver pResolver,
+                        Map functions,
+                        String defaultPrefix,
+                        Logger pLogger)
+    throws ELException
+  {
+    return mName;
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Returns the operator symbol
+   **/
+  String getOperatorSymbol ()
+  {
+    return ".";
+  }
+
+  //-------------------------------------
+  // ValueSuffix methods
+  //-------------------------------------
+  /**
+   *
+   * Returns the expression in the expression language syntax
+   **/
+  public String getExpressionString ()
+  {
+    return "." + StringLiteral.toIdentifierToken (mName);
+  }
+
+  //-------------------------------------
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/RelationalOperator.java b/standard/src/org/apache/taglibs/standard/lang/jstl/RelationalOperator.java
new file mode 100644
index 0000000..957c23e
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/RelationalOperator.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl;
+
+/**
+ *
+ * <p>This is the superclass for all relational operators (except ==
+ * or !=)
+ * 
+ * @author Nathan Abramson - Art Technology Group
+ * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: pierred $
+ **/
+
+public abstract class RelationalOperator
+  extends BinaryOperator
+{
+  //-------------------------------------
+  /**
+   *
+   * Applies the operator to the given value
+   **/
+  public Object apply (Object pLeft,
+		       Object pRight,
+		       Object pContext,
+		       Logger pLogger)
+    throws ELException
+  {
+    return Coercions.applyRelationalOperator (pLeft, pRight, this, pLogger);
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Applies the operator to the given double values
+   **/
+  public abstract boolean apply (double pLeft,
+				 double pRight,
+				 Logger pLogger);
+  
+  //-------------------------------------
+  /**
+   *
+   * Applies the operator to the given long values
+   **/
+  public abstract boolean apply (long pLeft,
+				 long pRight,
+				 Logger pLogger);
+  
+  //-------------------------------------
+  /**
+   *
+   * Applies the operator to the given String values
+   **/
+  public abstract boolean apply (String pLeft,
+				 String pRight,
+				 Logger pLogger);
+
+  //-------------------------------------
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/Resources.properties b/standard/src/org/apache/taglibs/standard/lang/jstl/Resources.properties
new file mode 100644
index 0000000..3361c5e
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/Resources.properties
@@ -0,0 +1,141 @@
+EXCEPTION_GETTING_BEANINFO=\
+	An Exception occurred getting the BeanInfo for class {0}
+
+NULL_EXPRESSION_STRING=\
+	A null expression string may not be passed to the \
+	expression evaluator
+
+PARSE_EXCEPTION=\
+	Encountered "{1}", expected one of [{0}]
+
+CANT_GET_PROPERTY_OF_NULL=\
+	Attempt to get property "{0}" from a null value
+
+NO_SUCH_PROPERTY=\
+	Class {0} does not have a property "{1}"
+
+NO_GETTER_METHOD=\
+	Property "{0}" of class {1} does not have a public getter method
+
+ERROR_GETTING_PROPERTY=\
+	An error occurred while getting property "{0}" from an instance \
+	of class {1}
+
+CANT_GET_INDEXED_VALUE_OF_NULL=\
+	Attempt to apply the "{0}" operator to a null value
+
+CANT_GET_NULL_INDEX=\
+	Attempt to apply a null index to the "{0}" operator
+
+NULL_INDEX=\
+	The index supplied to the "{0}" operator may not be null
+
+BAD_INDEX_VALUE=\
+	The "{0}" operator was supplied with an index value of type \
+	"{1}" to be applied to a List or array, but \
+	that value cannot be converted to an integer.
+
+EXCEPTION_ACCESSING_LIST=\
+	An exception occurred while trying to access index {0} of a \
+	List
+
+EXCEPTION_ACCESSING_ARRAY=\
+	An exception occurred while trying to access index {0} of an \
+	Array
+
+CANT_FIND_INDEX=\
+	Unable to find a value for "{0}" in object of class "{1}" using \
+	operator "{2}"
+
+TOSTRING_EXCEPTION=\
+	An object of type "{0}" threw an exception in its toString() \
+	method while trying to be coerced to a String
+
+BOOLEAN_TO_NUMBER=\
+	Attempt to coerce a boolean value "{0}" to type \
+	"{1}"
+
+STRING_TO_NUMBER_EXCEPTION=\
+	An exception occured trying to convert String "{0}" to type "{1}"
+
+COERCE_TO_NUMBER=\
+	Attempt to coerce a value of type "{0}" to type "{1}"
+
+BOOLEAN_TO_CHARACTER=\
+	Attempt to coerce a boolean value "{0}" to type Character
+
+EMPTY_STRING_TO_CHARACTER=\
+	Attempt to coerce an empty String to type Character
+
+COERCE_TO_CHARACTER=\
+	Attempt to coerce a value of type "{0}" to Character
+
+NULL_TO_BOOLEAN=\
+	Attempt to coerce a null value to a Boolean
+
+STRING_TO_BOOLEAN=\
+	An exception occurred trying to convert String "{0}" to type Boolean
+
+COERCE_TO_BOOLEAN=\
+	Attempt to coerce a value of type "{0}" to Boolean
+
+COERCE_TO_OBJECT=\
+	Attempt to coerce a value of type "{0}" to type "{1}"
+
+NO_PROPERTY_EDITOR=\
+	Attempt to convert String "{0}" to type "{1}", but there is \
+	no PropertyEditor for that type
+
+PROPERTY_EDITOR_ERROR=\
+	Unable to parse value "{0}" into expected type "{1}"
+
+ARITH_OP_NULL=\
+	Attempt to apply operator "{0}" to null value
+
+ARITH_OP_BAD_TYPE=\
+	Attempt to apply operator "{0}" to arguments of type "{1}" \
+	and "{2}"
+
+ARITH_ERROR=\
+	An error occurred applying operator "{0}" to operands "{1}" \
+	and "{2}"
+
+ERROR_IN_EQUALS=
+	An error occurred calling equals() on an object of type "{0}" \
+	when comparing with an object of type "{1}" for operator "{2}"
+
+UNARY_OP_BAD_TYPE=\
+	Attempt to apply operator "{0}" to arguments of type "{1}"
+
+NAMED_VALUE_NOT_FOUND=\
+	Unable to find a value for name "{0}"
+
+CANT_GET_INDEXED_PROPERTY=\
+	An error occurred obtaining the indexed property value of an \
+	object of type "{0}" with index "{1}"
+
+COMPARABLE_ERROR=\
+	An exception occurred while trying to compare a value of \
+	Comparable type "{0}" with a value of type "{1}" for operator \
+	"{2}"
+
+BAD_IMPLICIT_OBJECT=\
+	No such implicit object "{0}" - the only implicit objects are: \
+	{1}
+
+ATTRIBUTE_EVALUATION_EXCEPTION=\
+	An error occurred while evaluating custom action attribute "{0}" \
+	with value "{1}": {2} ({3})
+
+ATTRIBUTE_PARSE_EXCEPTION=\
+	An error occurred while parsing custom action attribute "{0}" \
+	with value "{1}": {2}
+
+UNKNOWN_FUNCTION=\
+	No function is mapped to the name "{1}"
+
+INAPPROPRIATE_FUNCTION_ARG_COUNT=\
+	The function "{1}" requires {2} arguments but was passed {3}
+
+FUNCTION_INVOCATION_ERROR=\
+	An error occurred while evaluating function "{0}"
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/Resources_ja.properties b/standard/src/org/apache/taglibs/standard/lang/jstl/Resources_ja.properties
new file mode 100644
index 0000000..d6ecefc
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/Resources_ja.properties
@@ -0,0 +1,122 @@
+EXCEPTION_GETTING_BEANINFO=\
+	\u30af\u30e9\u30b9 {0} \u306e BeanInfo \u3092\u53d6\u5f97\u3059\u308b\u904e\u7a0b\u3067\u4f8b\u5916\u304c\u767a\u751f\u3057\u307e\u3057\u305f
+
+NULL_EXPRESSION_STRING=\
+	null \u306e\u5f0f\u6587\u5b57\u5217\u306f\u3001\u5f0f\u306e\u8a55\u4fa1\u3068\u3057\u3066\u901a\u3089\u306a\u3044\u304b\u3082\u3057\u308c\u307e\u305b\u3093
+
+PARSE_EXCEPTION=\
+	[{0}] \u306e\uff11\u3064\u3092\u671f\u5f85\u3057\u307e\u3057\u305f\u304c\u3001"{1}" \u306b\u906d\u9047\u3057\u307e\u3057\u305f
+
+CANT_GET_PROPERTY_OF_NULL=\
+	null \u5024\u3088\u308a\u30d7\u30ed\u30d1\u30c6\u30a3 "{0}" \u3092\u53d6\u5f97\u3057\u3088\u3046\u3068\u3057\u3066\u3044\u307e\u3059
+
+NO_SUCH_PROPERTY=\
+	\u30af\u30e9\u30b9 {0} \u306b\u306f\u3001\u30d7\u30ed\u30d1\u30c6\u30a3 "{1}" \u304c\u5b58\u5728\u3057\u307e\u305b\u3093
+
+NO_GETTER_METHOD=\
+	\u30af\u30e9\u30b9 {1} \u306b\u3042\u308b\u30d7\u30ed\u30d1\u30c6\u30a3 "{0}" \u7528\u306e public \u3067\u5ba3\u8a00\u3055\u308c\u305f getter \u30e1\u30bd\u30c3\u30c9\u304c\u3042\u308a\u307e\u305b\u3093
+
+ERROR_GETTING_PROPERTY=\
+	\u30af\u30e9\u30b9 {1} \u306e\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u304b\u3089\u30d7\u30ed\u30d1\u30c6\u30a3 "{0}" \u3092\u53d6\u5f97\u3057\u3088\u3046\u3068\u3057\u3066\u3044\u308b\u904e\u7a0b\u3067\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f
+
+CANT_GET_INDEXED_VALUE_OF_NULL=\
+	null \u5024\u306b\u5bfe\u3057\u3066 "{0}" \u30aa\u30da\u30ec\u30fc\u30bf\u3092\u9069\u7528\u3057\u3088\u3046\u3068\u3057\u3066\u3044\u307e\u3059
+
+CANT_GET_NULL_INDEX=\
+	"{0}" \u30aa\u30da\u30ec\u30fc\u30bf\u306b\u5bfe\u3057\u3066 null \u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u3092\u9069\u7528\u3057\u3088\u3046\u3068\u3057\u3066\u3044\u307e\u3059
+
+NULL_INDEX=\
+	"{0}" \u30aa\u30da\u30ec\u30fc\u30bf\u306b\u5bfe\u3057\u3066\u4f9b\u7d66\u3055\u308c\u305f\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u306f null \u3067\u3042\u3063\u3066\u306f\u3044\u3051\u307e\u305b\u3093
+
+BAD_INDEX_VALUE=\
+	"{0}" \u30aa\u30da\u30ec\u30fc\u30bf\u306b\u3088\u3063\u3066 List \u3082\u3057\u304f\u306f\u914d\u5217\u306b\u9069\u7528\u3055\u308c\u305f "{1}" \u578b\u306e\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u5024\u3092\u4f9b\u7d66\u3057\u307e\u3057\u305f\u304c\u3001\u305d\u306e\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u5024\u3092\u6574\u6570\u5024\u3078\u5909\u63db\u3059\u308b\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093
+
+EXCEPTION_ACCESSING_LIST=\
+	List \u306e\u4e2d\u306e\u30a4\u30f3\u30c7\u30c3\u30af\u30b9 {0} \u3078\u30a2\u30af\u30bb\u30b9\u3057\u3088\u3046\u3068\u3057\u3066\u3044\u308b\u904e\u7a0b\u3067\u4f8b\u5916\u304c\u767a\u751f\u3057\u307e\u3057\u305f
+
+EXCEPTION_ACCESSING_ARRAY=\
+	Array \u306e\u4e2d\u306e\u30a4\u30f3\u30c7\u30c3\u30af\u30b9 {0} \u3078\u30a2\u30af\u30bb\u30b9\u3057\u3088\u3046\u3068\u3057\u3066\u3044\u308b\u904e\u7a0b\u3067\u4f8b\u5916\u304c\u767a\u751f\u3057\u307e\u3057\u305f
+
+CANT_FIND_INDEX=\
+	\u30aa\u30da\u30ec\u30fc\u30bf "{2}" \u3092\u5229\u7528\u3057\u307e\u3057\u305f\u304c\u3001\u30af\u30e9\u30b9 "{1}" \u306e\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306b\u304a\u3044\u3066 "{0}" \u306b\u5bfe\u5fdc\u3059\u308b\u5024\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093
+
+TOSTRING_EXCEPTION=\
+	"{0}" \u578b\u306e\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u3092 String \u306b\u5909\u63db\u3059\u308b\u904e\u7a0b\u306b\u304a\u3044\u3066\u3001\u3053\u306e\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306e toString() \u30e1\u30bd\u30c3\u30c9\u304c\u4f8b\u5916\u3092\u30b9\u30ed\u30fc\u3057\u307e\u3057\u305f
+
+BOOLEAN_TO_NUMBER=\
+	boolean \u5024 "{0}" \u3092 "{1}" \u578b\u306b\u5909\u63db\u3057\u3088\u3046\u3068\u3057\u3066\u3044\u307e\u3059
+
+STRING_TO_NUMBER_EXCEPTION=\
+	String "{0}" \u3092 "{1}" \u578b\u306b\u5909\u63db\u3057\u3088\u3046\u3068\u3057\u305f\u969b\u306b\u4f8b\u5916\u304c\u767a\u751f\u3057\u307e\u3057\u305f
+
+COERCE_TO_NUMBER=\
+	"{0}" \u578b\u306e\u5024\u3092 "{1}" \u578b\u306b\u5909\u63db\u3057\u3088\u3046\u3068\u3057\u3066\u3044\u307e\u3059
+
+BOOLEAN_TO_CHARACTER=\
+	boolean \u5024 "{0}" \u3092 Character \u578b\u306b\u5909\u63db\u3057\u3088\u3046\u3068\u3057\u3066\u3044\u307e\u3059
+
+EMPTY_STRING_TO_CHARACTER=\
+	\u7a7a\u306e String \u3092 Character \u578b\u306b\u5909\u63db\u3057\u3088\u3046\u3068\u3057\u3066\u3044\u307e\u3059
+
+COERCE_TO_CHARACTER=\
+	"{0}" \u578b\u306e\u5024\u3092 Character \u578b\u306b\u5909\u63db\u3057\u3088\u3046\u3068\u3057\u3066\u3044\u307e\u3059
+
+NULL_TO_BOOLEAN=\
+	null \u5024\u3092 Boolean \u578b\u306b\u5909\u63db\u3057\u3088\u3046\u3068\u3057\u3066\u3044\u307e\u3059
+
+STRING_TO_BOOLEAN=\
+	String "{0}" \u3092 Boolean \u578b\u306b\u5909\u63db\u3057\u3088\u3046\u3068\u3057\u305f\u969b\u306b\u4f8b\u5916\u304c\u767a\u751f\u3057\u307e\u3057\u305f
+
+COERCE_TO_BOOLEAN=\
+	"{0}" \u578b\u306e\u5024\u3092 Boolean \u578b\u306b\u5909\u63db\u3057\u3088\u3046\u3068\u3057\u3066\u3044\u307e\u3059
+
+COERCE_TO_OBJECT=\
+	"{0}" \u578b\u306e\u5024\u3092 "{1}" \u578b\u306b\u5909\u63db\u3057\u3088\u3046\u3068\u3057\u3066\u3044\u307e\u3059
+
+NO_PROPERTY_EDITOR=\
+	String "{0}" \u3092 "{1}" \u578b\u306b\u5909\u63db\u3057\u3088\u3046\u3068\u3057\u307e\u3057\u305f\u304c\u3001\u305d\u306e\u578b\u306b\u5bfe\u5fdc\u3059\u308b PropertyEditor \u304c\u5b58\u5728\u3057\u307e\u305b\u3093
+
+PROPERTY_EDITOR_ERROR=\
+	\u5024 "{0}" \u3092\u69cb\u6587\u89e3\u6790\u3057\u307e\u3057\u305f\u304c\u3001\u671f\u5f85\u3055\u308c\u308b "{1}" \u578b\u306b\u3059\u308b\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093
+
+ARITH_OP_NULL=\
+	null \u5024\u306b\u5bfe\u3057\u3066\u30aa\u30da\u30ec\u30fc\u30bf "{0}" \u3092\u9069\u7528\u3057\u3088\u3046\u3068\u3057\u3066\u3044\u307e\u3059
+
+ARITH_OP_BAD_TYPE=\
+	"{1}" \u578b\u304a\u3088\u3073 "{2}" \u578b\u306e\u5909\u6570\u306b\u5bfe\u3057\u3066\u30aa\u30da\u30ec\u30fc\u30bf "{0}" \u3092\u9069\u7528\u3057\u3088\u3046\u3068\u3057\u3066\u3044\u307e\u3059
+
+ARITH_ERROR=\
+	\u30aa\u30da\u30e9\u30f3\u30c9 "{1}" \u304a\u3088\u3073 "{2}" \u306b\u5bfe\u3057\u3066\u30aa\u30da\u30ec\u30fc\u30bf {0} \u3092\u9069\u7528\u3057\u3066\u3044\u308b\u904e\u7a0b\u3067\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f
+
+ERROR_IN_EQUALS=\
+	\u30aa\u30da\u30ec\u30fc\u30bf "{2}" \u306b\u5bfe\u3057\u3066 "{1}" \u578b\u306e\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u3068\u6bd4\u8f03\u3057\u3088\u3046\u3068\u3057\u307e\u3057\u305f\u304c\u3001"{0}" \u578b\u306e\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306e equals() \u30e1\u30bd\u30c3\u30c9\u3092\u547c\u3073\u51fa\u3057\u3066\u3044\u308b\u904e\u7a0b\u3067\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f
+
+UNARY_OP_BAD_TYPE=\
+	"{1}" \u578b\u306e\u5909\u6570\u306b\u5bfe\u3057\u3066\u30aa\u30da\u30ec\u30fc\u30bf "{0}" \u3092\u9069\u7528\u3057\u3088\u3046\u3068\u3057\u3066\u3044\u307e\u3059
+
+NAMED_VALUE_NOT_FOUND=\
+	\u540d\u79f0 "{0}" \u306b\u5bfe\u5fdc\u3059\u308b\u5024\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093
+
+CANT_GET_INDEXED_PROPERTY=\
+	\u30a4\u30f3\u30c7\u30c3\u30af\u30b9 "{1}" \u3092\u4ed8\u4e0e\u3057\u305f "{0}" \u578b\u306e\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306e\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u30fb\u30d7\u30ed\u30d1\u30c6\u30a3\u5024\u3092\u5f97\u3088\u3046\u3068\u3057\u305f\u904e\u7a0b\u3067\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f
+
+COMPARABLE_ERROR=\
+	\u30aa\u30da\u30ec\u30fc\u30bf "{2}" \u306b\u5bfe\u3057\u3066 Comparable \u578b\u3067\u3042\u308b "{0}" \u306e\u5024\u3068 "{1}" \u578b\u306e\u5024\u3068\u3092\u6bd4\u8f03\u3057\u3088\u3046\u3068\u3057\u3066\u3044\u308b\u904e\u7a0b\u3067\u4f8b\u5916\u304c\u767a\u751f\u3057\u307e\u3057\u305f
+
+BAD_IMPLICIT_OBJECT=\
+	\u305d\u306e\u3088\u3046\u306a\u6697\u9ed9\u30aa\u30d6\u30b8\u30a7\u30af\u30c8 "{0}" \u306f\u5b58\u5728\u3057\u307e\u305b\u3093 - \u552f\u4e00\u306e\u6697\u9ed9\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306f\u6b21\u306e\u3088\u3046\u306b\u306a\u308a\u307e\u3059: {1}
+
+ATTRIBUTE_EVALUATION_EXCEPTION=\
+	\u5024 "{1}" \u306e\u30bb\u30c3\u30c8\u3055\u308c\u305f\u30ab\u30b9\u30bf\u30e0\u30fb\u30a2\u30af\u30b7\u30e7\u30f3\u5c5e\u6027 "{0}" \u3092\u8a55\u4fa1\u3057\u3066\u3044\u308b\u904e\u7a0b\u3067\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f: {2} ({3})
+
+ATTRIBUTE_PARSE_EXCEPTION=\
+	\u5024 "{1}" \u306e\u30bb\u30c3\u30c8\u3055\u308c\u305f\u30ab\u30b9\u30bf\u30e0\u30fb\u30a2\u30af\u30b7\u30e7\u30f3\u5c5e\u6027 "{0}" \u3092\u69cb\u6587\u89e3\u6790\u3057\u3066\u3044\u308b\u904e\u7a0b\u3067\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f: {2}
+
+UNKNOWN_FUNCTION=\
+	"{1}" \u3068\u3044\u3046\u95a2\u6570\u540d\u306f\u5b58\u5728\u3057\u307e\u305b\u3093\u3002
+
+INAPPROPRIATE_FUNCTION_ARG_COUNT=\
+	\u95a2\u6570 "{1}" \u3067\u306f\u3001{2}\u500b\u306e\u5f15\u6570\u3092\u5fc5\u8981\u3068\u3057\u307e\u3059\u304c\u3001{3} \u3092\u901a\u3057\u307e\u3057\u305f\u3002
+
+FUNCTION_INVOCATION_ERROR=\
+	\u95a2\u6570 "{0}" \u3092\u8a55\u4fa1\u3057\u3066\u3044\u308b\u904e\u7a0b\u3067\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/StringLiteral.java b/standard/src/org/apache/taglibs/standard/lang/jstl/StringLiteral.java
new file mode 100644
index 0000000..22d92aa
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/StringLiteral.java
@@ -0,0 +1,183 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl;
+
+/**
+ *
+ * <p>An expression representing a String literal value.
+ * 
+ * @author Nathan Abramson - Art Technology Group
+ * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: pierred $
+ **/
+
+public class StringLiteral
+  extends Literal
+{
+  //-------------------------------------
+  /**
+   *
+   * Constructor
+   **/
+  StringLiteral (Object pValue)
+  {
+    super (pValue);
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Returns a StringLiteral parsed from the given token (enclosed by
+   * single or double quotes)
+   **/
+  public static StringLiteral fromToken (String pToken)
+  {
+    return new StringLiteral (getValueFromToken (pToken));
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Returns a StringLiteral with the given string value
+   **/
+  public static StringLiteral fromLiteralValue (String pValue)
+  {
+    return new StringLiteral (pValue);
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Parses the given token into the literal value
+   **/
+  public static String getValueFromToken (String pToken)
+  {
+    StringBuffer buf = new StringBuffer ();
+    int len = pToken.length () - 1;
+    boolean escaping = false;
+    for (int i = 1; i < len; i++) {
+      char ch = pToken.charAt (i);
+      if (escaping) {
+	buf.append (ch);
+	escaping = false;
+      }
+      else if (ch == '\\') {
+	escaping = true;
+      }
+      else {
+	buf.append (ch);
+      }
+    }
+    return buf.toString ();
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Converts the specified value to a String token, using " as the
+   * enclosing quotes and escaping any characters that need escaping.
+   **/
+  public static String toStringToken (String pValue)
+  {
+    // See if any escaping is needed
+    if (pValue.indexOf ('\"') < 0 &&
+	pValue.indexOf ('\\') < 0) {
+      return "\"" + pValue + "\"";
+    }
+
+    // Escaping is needed
+    else {
+      StringBuffer buf = new StringBuffer ();
+      buf.append ('\"');
+      int len = pValue.length ();
+      for (int i = 0; i < len; i++) {
+	char ch = pValue.charAt (i);
+	if (ch == '\\') {
+	  buf.append ('\\');
+	  buf.append ('\\');
+	}
+	else if (ch == '\"') {
+	  buf.append ('\\');
+	  buf.append ('\"');
+	}
+	else {
+	  buf.append (ch);
+	}
+      }
+      buf.append ('\"');
+      return buf.toString ();
+    }
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Converts the specified value to an identifier token, escaping it
+   * as a string literal if necessary.
+   **/
+  public static String toIdentifierToken (String pValue)
+  {
+    // See if it's a valid java identifier
+    if (isJavaIdentifier (pValue)) {
+      return pValue;
+    }
+
+    // Return as a String literal
+    else {
+      return toStringToken (pValue);
+    }
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Returns true if the specified value is a legal java identifier
+   **/
+  static boolean isJavaIdentifier (String pValue)
+  {
+    int len = pValue.length ();
+    if (len == 0) {
+      return false;
+    }
+    else {
+      if (!Character.isJavaIdentifierStart (pValue.charAt (0))) {
+	return false;
+      }
+      else {
+	for (int i = 1; i < len; i++) {
+	  if (!Character.isJavaIdentifierPart (pValue.charAt (i))) {
+	    return false;
+	  }
+	}
+	return true;
+      }
+    }
+  }
+
+  //-------------------------------------
+  // Expression methods
+  //-------------------------------------
+  /**
+   *
+   * Returns the expression in the expression language syntax
+   **/
+  public String getExpressionString ()
+  {
+    return toStringToken ((String) getValue ());
+  }
+
+  //-------------------------------------
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/UnaryMinusOperator.java b/standard/src/org/apache/taglibs/standard/lang/jstl/UnaryMinusOperator.java
new file mode 100644
index 0000000..9ec7025
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/UnaryMinusOperator.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl;
+
+/**
+ *
+ * <p>The implementation of the unary minus operator
+ * 
+ * @author Nathan Abramson - Art Technology Group
+ * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: pierred $
+ **/
+
+public class UnaryMinusOperator
+  extends UnaryOperator
+{
+  //-------------------------------------
+  // Singleton
+  //-------------------------------------
+
+  public static final UnaryMinusOperator SINGLETON =
+    new UnaryMinusOperator ();
+
+  //-------------------------------------
+  /**
+   *
+   * Constructor
+   **/
+  public UnaryMinusOperator ()
+  {
+  }
+
+  //-------------------------------------
+  // Expression methods
+  //-------------------------------------
+  /**
+   *
+   * Returns the symbol representing the operator
+   **/
+  public String getOperatorSymbol ()
+  {
+    return "-";
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Applies the operator to the given value
+   **/
+  public Object apply (Object pValue,
+		       Object pContext,
+		       Logger pLogger)
+    throws ELException
+  {
+    if (pValue == null) {
+      /*
+      if (pLogger.isLoggingWarning ()) {
+	pLogger.logWarning
+	  (Constants.ARITH_OP_NULL,
+	   getOperatorSymbol ());
+      }
+      */
+      return PrimitiveObjects.getInteger (0);
+    }
+
+    else if (pValue instanceof String) {
+      if (Coercions.isFloatingPointString (pValue)) {
+	double dval =
+	  ((Number) 
+	   (Coercions.coerceToPrimitiveNumber 
+	    (pValue, Double.class, pLogger))).
+	  doubleValue ();
+	return PrimitiveObjects.getDouble (-dval);
+      }
+      else {
+	long lval =
+	  ((Number) 
+	   (Coercions.coerceToPrimitiveNumber 
+	    (pValue, Long.class, pLogger))).
+	  longValue ();
+	return PrimitiveObjects.getLong (-lval);
+      }
+    }
+
+    else if (pValue instanceof Byte) {
+      return PrimitiveObjects.getByte 
+	((byte) -(((Byte) pValue).byteValue ()));
+    }
+    else if (pValue instanceof Short) {
+      return PrimitiveObjects.getShort 
+	((short) -(((Short) pValue).shortValue ()));
+    }
+    else if (pValue instanceof Integer) {
+      return PrimitiveObjects.getInteger 
+	((int) -(((Integer) pValue).intValue ()));
+    }
+    else if (pValue instanceof Long) {
+      return PrimitiveObjects.getLong 
+	((long) -(((Long) pValue).longValue ()));
+    }
+    else if (pValue instanceof Float) {
+      return PrimitiveObjects.getFloat 
+	((float) -(((Float) pValue).floatValue ()));
+    }
+    else if (pValue instanceof Double) {
+      return PrimitiveObjects.getDouble 
+	((double) -(((Double) pValue).doubleValue ()));
+    }
+
+    else {
+      if (pLogger.isLoggingError ()) {
+	pLogger.logError
+	  (Constants.UNARY_OP_BAD_TYPE,
+	   getOperatorSymbol (),
+	   pValue.getClass ().getName ());
+      }
+      return PrimitiveObjects.getInteger (0);
+    }
+  }
+
+  //-------------------------------------
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/UnaryOperator.java b/standard/src/org/apache/taglibs/standard/lang/jstl/UnaryOperator.java
new file mode 100644
index 0000000..249cc9a
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/UnaryOperator.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl;
+
+/**
+ *
+ * <p>This is the superclass for all unary operators
+ * 
+ * @author Nathan Abramson - Art Technology Group
+ * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: pierred $
+ **/
+
+public abstract class UnaryOperator
+{
+  //-------------------------------------
+  /**
+   *
+   * Constructor
+   **/
+  public UnaryOperator ()
+  {
+  }
+
+  //-------------------------------------
+  // Expression methods
+  //-------------------------------------
+  /**
+   *
+   * Returns the symbol representing the operator
+   **/
+  public abstract String getOperatorSymbol ();
+
+  //-------------------------------------
+  /**
+   *
+   * Applies the operator to the given value
+   **/
+  public abstract Object apply (Object pValue,
+				Object pContext,
+				Logger pLogger)
+    throws ELException;
+
+  //-------------------------------------
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/UnaryOperatorExpression.java b/standard/src/org/apache/taglibs/standard/lang/jstl/UnaryOperatorExpression.java
new file mode 100644
index 0000000..77b28bb
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/UnaryOperatorExpression.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ *
+ * <p>An expression representing one or more unary operators on a
+ * value
+ * 
+ * @author Nathan Abramson - Art Technology Group
+ * @author Shawn Bayern
+ * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: pierred $
+ **/
+
+public class UnaryOperatorExpression
+  extends Expression
+{
+  //-------------------------------------
+  // Properties
+  //-------------------------------------
+  // property operator
+
+  UnaryOperator mOperator;
+  public UnaryOperator getOperator ()
+  { return mOperator; }
+  public void setOperator (UnaryOperator pOperator)
+  { mOperator = pOperator; }
+
+  //-------------------------------------
+  // property operators
+
+  List mOperators;
+  public List getOperators ()
+  { return mOperators; }
+  public void setOperators (List pOperators)
+  { mOperators = pOperators; }
+
+  //-------------------------------------
+  // property expression
+
+  Expression mExpression;
+  public Expression getExpression ()
+  { return mExpression; }
+  public void setExpression (Expression pExpression)
+  { mExpression = pExpression; }
+
+  //-------------------------------------
+  /**
+   *
+   * Constructor
+   **/
+  public UnaryOperatorExpression (UnaryOperator pOperator,
+				  List pOperators,
+				  Expression pExpression)
+  {
+    mOperator = pOperator;
+    mOperators = pOperators;
+    mExpression = pExpression;
+  }
+
+  //-------------------------------------
+  // Expression methods
+  //-------------------------------------
+  /**
+   *
+   * Returns the expression in the expression language syntax
+   **/
+  public String getExpressionString ()
+  {
+    StringBuffer buf = new StringBuffer ();
+    buf.append ("(");
+    if (mOperator != null) {
+      buf.append (mOperator.getOperatorSymbol ());
+      buf.append (" ");
+    }
+    else {
+      for (int i = 0; i < mOperators.size (); i++) {
+	UnaryOperator operator = (UnaryOperator) mOperators.get (i);
+	buf.append (operator.getOperatorSymbol ());
+	buf.append (" ");
+      }
+    }
+    buf.append (mExpression.getExpressionString ());
+    buf.append (")");
+    return buf.toString ();
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Evaluates to the literal value
+   **/
+  public Object evaluate (Object pContext,
+			  VariableResolver pResolver,
+			  Map functions,
+			  String defaultPrefix,
+			  Logger pLogger)
+    throws ELException
+  {
+    Object value = mExpression.evaluate (pContext, pResolver, functions,
+					 defaultPrefix, pLogger);
+    if (mOperator != null) {
+      value = mOperator.apply (value, pContext, pLogger);
+    }
+    else {
+      for (int i = mOperators.size () - 1; i >= 0; i--) {
+	UnaryOperator operator = (UnaryOperator) mOperators.get (i);
+	value = operator.apply (value, pContext, pLogger);
+      }
+    }
+    return value;
+  }
+
+  //-------------------------------------
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/ValueSuffix.java b/standard/src/org/apache/taglibs/standard/lang/jstl/ValueSuffix.java
new file mode 100644
index 0000000..9faa6a3
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/ValueSuffix.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl;
+
+import java.util.Map;
+
+/**
+ *
+ * <p>Represents an element that can appear as a suffix in a complex
+ * value, such as a property or index operator, or a method call (should
+ * they ever need to be supported).
+ * 
+ * @author Nathan Abramson - Art Technology Group
+ * @author Shawn Bayern
+ * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: pierred $
+ **/
+
+public abstract class ValueSuffix
+{
+  //-------------------------------------
+  /**
+   *
+   * Returns the expression in the expression language syntax
+   **/
+  public abstract String getExpressionString ();
+
+  //-------------------------------------
+  /**
+   *
+   * Evaluates the expression in the given context, operating on the
+   * given value.
+   **/
+  public abstract Object evaluate (Object pValue,
+				   Object pContext,
+				   VariableResolver pResolver,
+				   Map functions,
+				   String defaultPrefix,
+				   Logger pLogger)
+    throws ELException;
+
+  //-------------------------------------
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/VariableResolver.java b/standard/src/org/apache/taglibs/standard/lang/jstl/VariableResolver.java
new file mode 100644
index 0000000..5292b9f
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/VariableResolver.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl;
+
+/**
+ *
+ * <p>This class is used to customize the way the evaluator resolves
+ * variable references.  For example, instances of this class can
+ * implement their own variable lookup mechanisms, or introduce the
+ * notion of "implicit variables" which override any other variables.
+ * An instance of this class should be passed to the evaluator's
+ * constructor.
+ *
+ * <p>Whenever the evaluator is invoked, it is passed a "context"
+ * Object from the application.  For example, in a JSP environment,
+ * the "context" is a PageContext.  That context object is eventually
+ * passed to this class, so that this class has a context in which to
+ * resolve variables.
+ * 
+ * @author Nathan Abramson - Art Technology Group
+ * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: pierred $
+ **/
+
+public interface VariableResolver
+{
+  //-------------------------------------
+  /**
+   *
+   * Resolves the specified variable within the given context.
+   * Returns null if the variable is not found.
+   **/
+  public Object resolveVariable (String pName,
+				 Object pContext)
+    throws ELException;
+					
+  //-------------------------------------
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/parser/ELParser.java b/standard/src/org/apache/taglibs/standard/lang/jstl/parser/ELParser.java
new file mode 100644
index 0000000..6034909
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/parser/ELParser.java
@@ -0,0 +1,1204 @@
+/* Generated By:JavaCC: Do not edit this line. ELParser.java */
+package org.apache.taglibs.standard.lang.jstl.parser;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.taglibs.standard.lang.jstl.AndOperator;
+import org.apache.taglibs.standard.lang.jstl.ArraySuffix;
+import org.apache.taglibs.standard.lang.jstl.BinaryOperator;
+import org.apache.taglibs.standard.lang.jstl.BinaryOperatorExpression;
+import org.apache.taglibs.standard.lang.jstl.BooleanLiteral;
+import org.apache.taglibs.standard.lang.jstl.ComplexValue;
+import org.apache.taglibs.standard.lang.jstl.DivideOperator;
+import org.apache.taglibs.standard.lang.jstl.EmptyOperator;
+import org.apache.taglibs.standard.lang.jstl.EqualsOperator;
+import org.apache.taglibs.standard.lang.jstl.Expression;
+import org.apache.taglibs.standard.lang.jstl.ExpressionString;
+import org.apache.taglibs.standard.lang.jstl.FloatingPointLiteral;
+import org.apache.taglibs.standard.lang.jstl.FunctionInvocation;
+import org.apache.taglibs.standard.lang.jstl.GreaterThanOperator;
+import org.apache.taglibs.standard.lang.jstl.GreaterThanOrEqualsOperator;
+import org.apache.taglibs.standard.lang.jstl.IntegerLiteral;
+import org.apache.taglibs.standard.lang.jstl.LessThanOperator;
+import org.apache.taglibs.standard.lang.jstl.LessThanOrEqualsOperator;
+import org.apache.taglibs.standard.lang.jstl.Literal;
+import org.apache.taglibs.standard.lang.jstl.MinusOperator;
+import org.apache.taglibs.standard.lang.jstl.ModulusOperator;
+import org.apache.taglibs.standard.lang.jstl.MultiplyOperator;
+import org.apache.taglibs.standard.lang.jstl.NamedValue;
+import org.apache.taglibs.standard.lang.jstl.NotEqualsOperator;
+import org.apache.taglibs.standard.lang.jstl.NotOperator;
+import org.apache.taglibs.standard.lang.jstl.NullLiteral;
+import org.apache.taglibs.standard.lang.jstl.OrOperator;
+import org.apache.taglibs.standard.lang.jstl.PlusOperator;
+import org.apache.taglibs.standard.lang.jstl.PropertySuffix;
+import org.apache.taglibs.standard.lang.jstl.StringLiteral;
+import org.apache.taglibs.standard.lang.jstl.UnaryMinusOperator;
+import org.apache.taglibs.standard.lang.jstl.UnaryOperator;
+import org.apache.taglibs.standard.lang.jstl.UnaryOperatorExpression;
+import org.apache.taglibs.standard.lang.jstl.ValueSuffix;
+
+/**
+ * Generated EL parser.
+ * 
+ * @author Nathan Abramson
+ * @author Shawn Bayern
+ */
+
+public class ELParser implements ELParserConstants {
+
+  public static void main(String args[])
+       throws ParseException
+  {
+    ELParser parser = new ELParser (System.in);
+    parser.ExpressionString ();
+  }
+
+/*****************************************
+ * GRAMMAR PRODUCTIONS *
+ *****************************************/
+
+/**
+ *
+ * Returns a String if the expression string is a single String, an
+ * Expression if the expression string is a single Expression, an
+ * ExpressionString if it's a mixture of both.
+ **/
+  final public Object ExpressionString() throws ParseException {
+  Object ret = "";
+  List elems = null;
+  Object elem;
+    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+    case NON_EXPRESSION_TEXT:
+      ret = AttrValueString();
+      break;
+    case START_EXPRESSION:
+      ret = AttrValueExpression();
+      break;
+    default:
+      jj_la1[0] = jj_gen;
+      jj_consume_token(-1);
+      throw new ParseException();
+    }
+    label_1:
+    while (true) {
+      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+      case NON_EXPRESSION_TEXT:
+      case START_EXPRESSION:
+        ;
+        break;
+      default:
+        jj_la1[1] = jj_gen;
+        break label_1;
+      }
+      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+      case NON_EXPRESSION_TEXT:
+        elem = AttrValueString();
+        break;
+      case START_EXPRESSION:
+        elem = AttrValueExpression();
+        break;
+      default:
+        jj_la1[2] = jj_gen;
+        jj_consume_token(-1);
+        throw new ParseException();
+      }
+       if (elems == null) {
+         elems = new ArrayList ();
+         elems.add (ret);
+       }
+       elems.add (elem);
+    }
+    if (elems != null) {
+      ret = new ExpressionString (elems.toArray ());
+    }
+    {if (true) return ret;}
+    throw new Error("Missing return statement in function");
+  }
+
+  final public String AttrValueString() throws ParseException {
+  Token t;
+    t = jj_consume_token(NON_EXPRESSION_TEXT);
+    {if (true) return t.image;}
+    throw new Error("Missing return statement in function");
+  }
+
+  final public Expression AttrValueExpression() throws ParseException {
+  Expression exp;
+    jj_consume_token(START_EXPRESSION);
+    exp = Expression();
+    jj_consume_token(END_EXPRESSION);
+     {if (true) return exp;}
+    throw new Error("Missing return statement in function");
+  }
+
+  final public Expression Expression() throws ParseException {
+  Expression ret;
+    ret = OrExpression();
+    {if (true) return ret;}
+    throw new Error("Missing return statement in function");
+  }
+
+  final public Expression OrExpression() throws ParseException {
+  Expression startExpression;
+  BinaryOperator operator;
+  Expression expression;
+  List operators = null;
+  List expressions = null;
+    startExpression = AndExpression();
+    label_2:
+    while (true) {
+      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+      case OR1:
+      case OR2:
+        ;
+        break;
+      default:
+        jj_la1[3] = jj_gen;
+        break label_2;
+      }
+      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+      case OR1:
+        jj_consume_token(OR1);
+        break;
+      case OR2:
+        jj_consume_token(OR2);
+        break;
+      default:
+        jj_la1[4] = jj_gen;
+        jj_consume_token(-1);
+        throw new ParseException();
+      }
+                        operator = OrOperator.SINGLETON;
+      expression = AndExpression();
+        if (operators == null) {
+          operators = new ArrayList ();
+          expressions = new ArrayList ();
+        }
+        operators.add (operator);
+        expressions.add (expression);
+    }
+    if (operators != null) {
+      {if (true) return new BinaryOperatorExpression (startExpression,
+                                           operators,
+                                           expressions);}
+    }
+    else {
+      {if (true) return startExpression;}
+    }
+    throw new Error("Missing return statement in function");
+  }
+
+  final public Expression AndExpression() throws ParseException {
+  Expression startExpression;
+  BinaryOperator operator;
+  Expression expression;
+  List operators = null;
+  List expressions = null;
+    startExpression = EqualityExpression();
+    label_3:
+    while (true) {
+      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+      case AND1:
+      case AND2:
+        ;
+        break;
+      default:
+        jj_la1[5] = jj_gen;
+        break label_3;
+      }
+      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+      case AND1:
+        jj_consume_token(AND1);
+        break;
+      case AND2:
+        jj_consume_token(AND2);
+        break;
+      default:
+        jj_la1[6] = jj_gen;
+        jj_consume_token(-1);
+        throw new ParseException();
+      }
+                          operator = AndOperator.SINGLETON;
+      expression = EqualityExpression();
+        if (operators == null) {
+          operators = new ArrayList ();
+          expressions = new ArrayList ();
+        }
+        operators.add (operator);
+        expressions.add (expression);
+    }
+    if (operators != null) {
+      {if (true) return new BinaryOperatorExpression (startExpression,
+                                           operators,
+                                           expressions);}
+    }
+    else {
+      {if (true) return startExpression;}
+    }
+    throw new Error("Missing return statement in function");
+  }
+
+  final public Expression EqualityExpression() throws ParseException {
+  Expression startExpression;
+  BinaryOperator operator;
+  Expression expression;
+  List operators = null;
+  List expressions = null;
+    startExpression = RelationalExpression();
+    label_4:
+    while (true) {
+      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+      case EQ1:
+      case EQ2:
+      case NE1:
+      case NE2:
+        ;
+        break;
+      default:
+        jj_la1[7] = jj_gen;
+        break label_4;
+      }
+      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+      case EQ1:
+      case EQ2:
+        switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+        case EQ1:
+          jj_consume_token(EQ1);
+          break;
+        case EQ2:
+          jj_consume_token(EQ2);
+          break;
+        default:
+          jj_la1[8] = jj_gen;
+          jj_consume_token(-1);
+          throw new ParseException();
+        }
+                        operator = EqualsOperator.SINGLETON;
+        break;
+      case NE1:
+      case NE2:
+        switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+        case NE1:
+          jj_consume_token(NE1);
+          break;
+        case NE2:
+          jj_consume_token(NE2);
+          break;
+        default:
+          jj_la1[9] = jj_gen;
+          jj_consume_token(-1);
+          throw new ParseException();
+        }
+                          operator = NotEqualsOperator.SINGLETON;
+        break;
+      default:
+        jj_la1[10] = jj_gen;
+        jj_consume_token(-1);
+        throw new ParseException();
+      }
+      expression = RelationalExpression();
+        if (operators == null) {
+          operators = new ArrayList ();
+          expressions = new ArrayList ();
+        }
+        operators.add (operator);
+        expressions.add (expression);
+    }
+    if (operators != null) {
+      {if (true) return new BinaryOperatorExpression (startExpression,
+                                           operators,
+                                           expressions);}
+    }
+    else {
+      {if (true) return startExpression;}
+    }
+    throw new Error("Missing return statement in function");
+  }
+
+  final public Expression RelationalExpression() throws ParseException {
+  Expression startExpression;
+  BinaryOperator operator;
+  Expression expression;
+  List operators = null;
+  List expressions = null;
+    startExpression = AddExpression();
+    label_5:
+    while (true) {
+      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+      case GT1:
+      case GT2:
+      case LT1:
+      case LT2:
+      case LE1:
+      case LE2:
+      case GE1:
+      case GE2:
+        ;
+        break;
+      default:
+        jj_la1[11] = jj_gen;
+        break label_5;
+      }
+      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+      case LT1:
+      case LT2:
+        switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+        case LT1:
+          jj_consume_token(LT1);
+          break;
+        case LT2:
+          jj_consume_token(LT2);
+          break;
+        default:
+          jj_la1[12] = jj_gen;
+          jj_consume_token(-1);
+          throw new ParseException();
+        }
+                        operator = LessThanOperator.SINGLETON;
+        break;
+      case GT1:
+      case GT2:
+        switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+        case GT1:
+          jj_consume_token(GT1);
+          break;
+        case GT2:
+          jj_consume_token(GT2);
+          break;
+        default:
+          jj_la1[13] = jj_gen;
+          jj_consume_token(-1);
+          throw new ParseException();
+        }
+                          operator = GreaterThanOperator.SINGLETON;
+        break;
+      case GE1:
+      case GE2:
+        switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+        case GE1:
+          jj_consume_token(GE1);
+          break;
+        case GE2:
+          jj_consume_token(GE2);
+          break;
+        default:
+          jj_la1[14] = jj_gen;
+          jj_consume_token(-1);
+          throw new ParseException();
+        }
+                          operator = GreaterThanOrEqualsOperator.SINGLETON;
+        break;
+      case LE1:
+      case LE2:
+        switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+        case LE1:
+          jj_consume_token(LE1);
+          break;
+        case LE2:
+          jj_consume_token(LE2);
+          break;
+        default:
+          jj_la1[15] = jj_gen;
+          jj_consume_token(-1);
+          throw new ParseException();
+        }
+                          operator = LessThanOrEqualsOperator.SINGLETON;
+        break;
+      default:
+        jj_la1[16] = jj_gen;
+        jj_consume_token(-1);
+        throw new ParseException();
+      }
+      expression = AddExpression();
+        if (operators == null) {
+          operators = new ArrayList ();
+          expressions = new ArrayList ();
+        }
+        operators.add (operator);
+        expressions.add (expression);
+    }
+    if (operators != null) {
+      {if (true) return new BinaryOperatorExpression (startExpression,
+                                           operators,
+                                           expressions);}
+    }
+    else {
+      {if (true) return startExpression;}
+    }
+    throw new Error("Missing return statement in function");
+  }
+
+  final public Expression AddExpression() throws ParseException {
+  Expression startExpression;
+  BinaryOperator operator;
+  Expression expression;
+  List operators = null;
+  List expressions = null;
+    startExpression = MultiplyExpression();
+    label_6:
+    while (true) {
+      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+      case PLUS:
+      case MINUS:
+        ;
+        break;
+      default:
+        jj_la1[17] = jj_gen;
+        break label_6;
+      }
+      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+      case PLUS:
+        jj_consume_token(PLUS);
+               operator = PlusOperator.SINGLETON;
+        break;
+      case MINUS:
+        jj_consume_token(MINUS);
+                  operator = MinusOperator.SINGLETON;
+        break;
+      default:
+        jj_la1[18] = jj_gen;
+        jj_consume_token(-1);
+        throw new ParseException();
+      }
+      expression = MultiplyExpression();
+        if (operators == null) {
+          operators = new ArrayList ();
+          expressions = new ArrayList ();
+        }
+        operators.add (operator);
+        expressions.add (expression);
+    }
+    if (operators != null) {
+      {if (true) return new BinaryOperatorExpression (startExpression,
+                                           operators,
+                                           expressions);}
+    }
+    else {
+      {if (true) return startExpression;}
+    }
+    throw new Error("Missing return statement in function");
+  }
+
+  final public Expression MultiplyExpression() throws ParseException {
+  Expression startExpression;
+  BinaryOperator operator;
+  Expression expression;
+  List operators = null;
+  List expressions = null;
+    startExpression = UnaryExpression();
+    label_7:
+    while (true) {
+      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+      case MULTIPLY:
+      case DIVIDE1:
+      case DIVIDE2:
+      case MODULUS1:
+      case MODULUS2:
+        ;
+        break;
+      default:
+        jj_la1[19] = jj_gen;
+        break label_7;
+      }
+      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+      case MULTIPLY:
+        jj_consume_token(MULTIPLY);
+                   operator = MultiplyOperator.SINGLETON;
+        break;
+      case DIVIDE1:
+      case DIVIDE2:
+        switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+        case DIVIDE1:
+          jj_consume_token(DIVIDE1);
+          break;
+        case DIVIDE2:
+          jj_consume_token(DIVIDE2);
+          break;
+        default:
+          jj_la1[20] = jj_gen;
+          jj_consume_token(-1);
+          throw new ParseException();
+        }
+                                  operator = DivideOperator.SINGLETON;
+        break;
+      case MODULUS1:
+      case MODULUS2:
+        switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+        case MODULUS1:
+          jj_consume_token(MODULUS1);
+          break;
+        case MODULUS2:
+          jj_consume_token(MODULUS2);
+          break;
+        default:
+          jj_la1[21] = jj_gen;
+          jj_consume_token(-1);
+          throw new ParseException();
+        }
+                                    operator = ModulusOperator.SINGLETON;
+        break;
+      default:
+        jj_la1[22] = jj_gen;
+        jj_consume_token(-1);
+        throw new ParseException();
+      }
+      expression = UnaryExpression();
+        if (operators == null) {
+          operators = new ArrayList ();
+          expressions = new ArrayList ();
+        }
+        operators.add (operator);
+        expressions.add (expression);
+    }
+    if (operators != null) {
+      {if (true) return new BinaryOperatorExpression (startExpression,
+                                           operators,
+                                           expressions);}
+    }
+    else {
+      {if (true) return startExpression;}
+    }
+    throw new Error("Missing return statement in function");
+  }
+
+  final public Expression UnaryExpression() throws ParseException {
+  Expression expression;
+  UnaryOperator singleOperator = null;
+  UnaryOperator operator;
+  List operators = null;
+    label_8:
+    while (true) {
+      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+      case MINUS:
+      case NOT1:
+      case NOT2:
+      case EMPTY:
+        ;
+        break;
+      default:
+        jj_la1[23] = jj_gen;
+        break label_8;
+      }
+      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+      case NOT1:
+      case NOT2:
+        switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+        case NOT1:
+          jj_consume_token(NOT1);
+          break;
+        case NOT2:
+          jj_consume_token(NOT2);
+          break;
+        default:
+          jj_la1[24] = jj_gen;
+          jj_consume_token(-1);
+          throw new ParseException();
+        }
+                        operator = NotOperator.SINGLETON;
+        break;
+      case MINUS:
+        jj_consume_token(MINUS);
+                operator = UnaryMinusOperator.SINGLETON;
+        break;
+      case EMPTY:
+        jj_consume_token(EMPTY);
+                operator = EmptyOperator.SINGLETON;
+        break;
+      default:
+        jj_la1[25] = jj_gen;
+        jj_consume_token(-1);
+        throw new ParseException();
+      }
+    if (singleOperator == null) {
+      singleOperator = operator;
+    }
+    else if (operators == null) {
+      operators = new ArrayList ();
+      operators.add (singleOperator);
+      operators.add (operator);
+    }
+    else {
+      operators.add (operator);
+    }
+    }
+    expression = Value();
+    if (operators != null) {
+      {if (true) return new UnaryOperatorExpression (null, operators, expression);}
+    }
+    else if (singleOperator != null) {
+      {if (true) return new UnaryOperatorExpression (singleOperator, null, expression);}
+    }
+    else {
+      {if (true) return expression;}
+    }
+    throw new Error("Missing return statement in function");
+  }
+
+  final public Expression Value() throws ParseException {
+  Expression prefix;
+  ValueSuffix suffix;
+  List suffixes = null;
+    prefix = ValuePrefix();
+    label_9:
+    while (true) {
+      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+      case DOT:
+      case LBRACKET:
+        ;
+        break;
+      default:
+        jj_la1[26] = jj_gen;
+        break label_9;
+      }
+      suffix = ValueSuffix();
+        if (suffixes == null) {
+          suffixes = new ArrayList ();
+        }
+        suffixes.add (suffix);
+    }
+    if (suffixes == null) {
+      {if (true) return prefix;}
+    }
+    else {
+      {if (true) return new ComplexValue (prefix, suffixes);}
+    }
+    throw new Error("Missing return statement in function");
+  }
+
+/**
+ * This is an element that can start a value
+ **/
+  final public Expression ValuePrefix() throws ParseException {
+  Expression ret;
+    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+    case INTEGER_LITERAL:
+    case FLOATING_POINT_LITERAL:
+    case STRING_LITERAL:
+    case TRUE:
+    case FALSE:
+    case NULL:
+      ret = Literal();
+      break;
+    case LPAREN:
+      jj_consume_token(LPAREN);
+      ret = Expression();
+      jj_consume_token(RPAREN);
+      break;
+    default:
+      jj_la1[27] = jj_gen;
+      if (jj_2_1(2147483647)) {
+        ret = FunctionInvocation();
+      } else {
+        switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+        case IDENTIFIER:
+          ret = NamedValue();
+          break;
+        default:
+          jj_la1[28] = jj_gen;
+          jj_consume_token(-1);
+          throw new ParseException();
+        }
+      }
+    }
+      {if (true) return ret;}
+    throw new Error("Missing return statement in function");
+  }
+
+  final public NamedValue NamedValue() throws ParseException {
+  Token t;
+    t = jj_consume_token(IDENTIFIER);
+                     {if (true) return new NamedValue (t.image);}
+    throw new Error("Missing return statement in function");
+  }
+
+  final public FunctionInvocation FunctionInvocation() throws ParseException {
+  String qualifiedName;
+  List argumentList = new ArrayList();
+  Expression exp;
+    qualifiedName = QualifiedName();
+    jj_consume_token(LPAREN);
+    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+    case INTEGER_LITERAL:
+    case FLOATING_POINT_LITERAL:
+    case STRING_LITERAL:
+    case TRUE:
+    case FALSE:
+    case NULL:
+    case LPAREN:
+    case MINUS:
+    case NOT1:
+    case NOT2:
+    case EMPTY:
+    case IDENTIFIER:
+      exp = Expression();
+          argumentList.add(exp);
+      label_10:
+      while (true) {
+        switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+        case COMMA:
+          ;
+          break;
+        default:
+          jj_la1[29] = jj_gen;
+          break label_10;
+        }
+        jj_consume_token(COMMA);
+        exp = Expression();
+          argumentList.add(exp);
+      }
+      break;
+    default:
+      jj_la1[30] = jj_gen;
+      ;
+    }
+    jj_consume_token(RPAREN);
+    String allowed = System.getProperty("javax.servlet.jsp.functions.allowed");
+    if (allowed == null || !allowed.equalsIgnoreCase("true"))
+      {if (true) throw new ParseException("EL functions are not supported.");}
+    {if (true) return new FunctionInvocation(qualifiedName, argumentList);}
+    throw new Error("Missing return statement in function");
+  }
+
+  final public ValueSuffix ValueSuffix() throws ParseException {
+  ValueSuffix suffix;
+    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+    case DOT:
+      suffix = PropertySuffix();
+      break;
+    case LBRACKET:
+      suffix = ArraySuffix();
+      break;
+    default:
+      jj_la1[31] = jj_gen;
+      jj_consume_token(-1);
+      throw new ParseException();
+    }
+      {if (true) return suffix;}
+    throw new Error("Missing return statement in function");
+  }
+
+  final public PropertySuffix PropertySuffix() throws ParseException {
+  Token t;
+  String property;
+    jj_consume_token(DOT);
+    property = Identifier();
+      {if (true) return new PropertySuffix (property);}
+    throw new Error("Missing return statement in function");
+  }
+
+  final public ArraySuffix ArraySuffix() throws ParseException {
+  Expression index;
+    jj_consume_token(LBRACKET);
+    index = Expression();
+    jj_consume_token(RBRACKET);
+     {if (true) return new ArraySuffix (index);}
+    throw new Error("Missing return statement in function");
+  }
+
+  final public Literal Literal() throws ParseException {
+  Literal ret;
+    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+    case TRUE:
+    case FALSE:
+      ret = BooleanLiteral();
+      break;
+    case INTEGER_LITERAL:
+      ret = IntegerLiteral();
+      break;
+    case FLOATING_POINT_LITERAL:
+      ret = FloatingPointLiteral();
+      break;
+    case STRING_LITERAL:
+      ret = StringLiteral();
+      break;
+    case NULL:
+      ret = NullLiteral();
+      break;
+    default:
+      jj_la1[32] = jj_gen;
+      jj_consume_token(-1);
+      throw new ParseException();
+    }
+      {if (true) return ret;}
+    throw new Error("Missing return statement in function");
+  }
+
+  final public BooleanLiteral BooleanLiteral() throws ParseException {
+    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+    case TRUE:
+      jj_consume_token(TRUE);
+           {if (true) return BooleanLiteral.TRUE;}
+      break;
+    case FALSE:
+      jj_consume_token(FALSE);
+              {if (true) return BooleanLiteral.FALSE;}
+      break;
+    default:
+      jj_la1[33] = jj_gen;
+      jj_consume_token(-1);
+      throw new ParseException();
+    }
+    throw new Error("Missing return statement in function");
+  }
+
+  final public StringLiteral StringLiteral() throws ParseException {
+  Token t;
+    t = jj_consume_token(STRING_LITERAL);
+    {if (true) return StringLiteral.fromToken (t.image);}
+    throw new Error("Missing return statement in function");
+  }
+
+  final public IntegerLiteral IntegerLiteral() throws ParseException {
+  Token t;
+    t = jj_consume_token(INTEGER_LITERAL);
+    {if (true) return new IntegerLiteral (t.image);}
+    throw new Error("Missing return statement in function");
+  }
+
+  final public FloatingPointLiteral FloatingPointLiteral() throws ParseException {
+  Token t;
+    t = jj_consume_token(FLOATING_POINT_LITERAL);
+    {if (true) return new FloatingPointLiteral (t.image);}
+    throw new Error("Missing return statement in function");
+  }
+
+  final public NullLiteral NullLiteral() throws ParseException {
+    jj_consume_token(NULL);
+      {if (true) return NullLiteral.SINGLETON;}
+    throw new Error("Missing return statement in function");
+  }
+
+  final public String Identifier() throws ParseException {
+  Token t;
+    t = jj_consume_token(IDENTIFIER);
+      {if (true) return t.image;}
+    throw new Error("Missing return statement in function");
+  }
+
+  final public String QualifiedName() throws ParseException {
+  String prefix = null, localPart = null;
+    if (jj_2_2(2147483647)) {
+      prefix = Identifier();
+      jj_consume_token(COLON);
+    } else {
+      ;
+    }
+    localPart = Identifier();
+    if (prefix == null)
+      {if (true) return localPart;}
+    else
+     {if (true) return prefix + ":" + localPart;}
+    throw new Error("Missing return statement in function");
+  }
+
+  final private boolean jj_2_1(int xla) {
+    jj_la = xla; jj_lastpos = jj_scanpos = token;
+    boolean retval = !jj_3_1();
+    jj_save(0, xla);
+    return retval;
+  }
+
+  final private boolean jj_2_2(int xla) {
+    jj_la = xla; jj_lastpos = jj_scanpos = token;
+    boolean retval = !jj_3_2();
+    jj_save(1, xla);
+    return retval;
+  }
+
+  final private boolean jj_3R_13() {
+    if (jj_3R_12()) return true;
+    if (jj_la == 0 && jj_scanpos == jj_lastpos) return false;
+    if (jj_scan_token(COLON)) return true;
+    if (jj_la == 0 && jj_scanpos == jj_lastpos) return false;
+    return false;
+  }
+
+  final private boolean jj_3_2() {
+    if (jj_3R_12()) return true;
+    if (jj_la == 0 && jj_scanpos == jj_lastpos) return false;
+    if (jj_scan_token(COLON)) return true;
+    if (jj_la == 0 && jj_scanpos == jj_lastpos) return false;
+    return false;
+  }
+
+  final private boolean jj_3_1() {
+    if (jj_3R_11()) return true;
+    if (jj_la == 0 && jj_scanpos == jj_lastpos) return false;
+    if (jj_scan_token(LPAREN)) return true;
+    if (jj_la == 0 && jj_scanpos == jj_lastpos) return false;
+    return false;
+  }
+
+  final private boolean jj_3R_12() {
+    if (jj_scan_token(IDENTIFIER)) return true;
+    if (jj_la == 0 && jj_scanpos == jj_lastpos) return false;
+    return false;
+  }
+
+  final private boolean jj_3R_11() {
+    Token xsp;
+    xsp = jj_scanpos;
+    if (jj_3R_13()) jj_scanpos = xsp;
+    else if (jj_la == 0 && jj_scanpos == jj_lastpos) return false;
+    if (jj_3R_12()) return true;
+    if (jj_la == 0 && jj_scanpos == jj_lastpos) return false;
+    return false;
+  }
+
+  public ELParserTokenManager token_source;
+  SimpleCharStream jj_input_stream;
+  public Token token, jj_nt;
+  private int jj_ntk;
+  private Token jj_scanpos, jj_lastpos;
+  private int jj_la;
+  public boolean lookingAhead = false;
+  private boolean jj_semLA;
+  private int jj_gen;
+  final private int[] jj_la1 = new int[34];
+  final private int[] jj_la1_0 = {0x6,0x6,0x6,0x0,0x0,0x0,0x0,0x18600000,0x600000,0x18000000,0x18600000,0x79e0000,0x180000,0x60000,0x6000000,0x1800000,0x79e0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x10000,0x20007580,0x0,0x80000000,0x20007580,0x10000,0x7580,0x3000,};
+  final private int[] jj_la1_1 = {0x0,0x0,0x0,0xc000,0xc000,0x3000,0x3000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x18,0x18,0x3e0,0xc0,0x300,0x3e0,0x10c10,0xc00,0x10c10,0x2,0x0,0x20000,0x0,0x30c10,0x2,0x0,0x0,};
+  final private JJCalls[] jj_2_rtns = new JJCalls[2];
+  private boolean jj_rescan = false;
+  private int jj_gc = 0;
+
+  public ELParser(java.io.InputStream stream) {
+    jj_input_stream = new SimpleCharStream(stream, 1, 1);
+    token_source = new ELParserTokenManager(jj_input_stream);
+    token = new Token();
+    jj_ntk = -1;
+    jj_gen = 0;
+    for (int i = 0; i < 34; i++) jj_la1[i] = -1;
+    for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
+  }
+
+  public void ReInit(java.io.InputStream stream) {
+    jj_input_stream.ReInit(stream, 1, 1);
+    token_source.ReInit(jj_input_stream);
+    token = new Token();
+    jj_ntk = -1;
+    jj_gen = 0;
+    for (int i = 0; i < 34; i++) jj_la1[i] = -1;
+    for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
+  }
+
+  public ELParser(java.io.Reader stream) {
+    jj_input_stream = new SimpleCharStream(stream, 1, 1);
+    token_source = new ELParserTokenManager(jj_input_stream);
+    token = new Token();
+    jj_ntk = -1;
+    jj_gen = 0;
+    for (int i = 0; i < 34; i++) jj_la1[i] = -1;
+    for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
+  }
+
+  public void ReInit(java.io.Reader stream) {
+    jj_input_stream.ReInit(stream, 1, 1);
+    token_source.ReInit(jj_input_stream);
+    token = new Token();
+    jj_ntk = -1;
+    jj_gen = 0;
+    for (int i = 0; i < 34; i++) jj_la1[i] = -1;
+    for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
+  }
+
+  public ELParser(ELParserTokenManager tm) {
+    token_source = tm;
+    token = new Token();
+    jj_ntk = -1;
+    jj_gen = 0;
+    for (int i = 0; i < 34; i++) jj_la1[i] = -1;
+    for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
+  }
+
+  public void ReInit(ELParserTokenManager tm) {
+    token_source = tm;
+    token = new Token();
+    jj_ntk = -1;
+    jj_gen = 0;
+    for (int i = 0; i < 34; i++) jj_la1[i] = -1;
+    for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
+  }
+
+  final private Token jj_consume_token(int kind) throws ParseException {
+    Token oldToken;
+    if ((oldToken = token).next != null) token = token.next;
+    else token = token.next = token_source.getNextToken();
+    jj_ntk = -1;
+    if (token.kind == kind) {
+      jj_gen++;
+      if (++jj_gc > 100) {
+        jj_gc = 0;
+        for (int i = 0; i < jj_2_rtns.length; i++) {
+          JJCalls c = jj_2_rtns[i];
+          while (c != null) {
+            if (c.gen < jj_gen) c.first = null;
+            c = c.next;
+          }
+        }
+      }
+      return token;
+    }
+    token = oldToken;
+    jj_kind = kind;
+    throw generateParseException();
+  }
+
+  final private boolean jj_scan_token(int kind) {
+    if (jj_scanpos == jj_lastpos) {
+      jj_la--;
+      if (jj_scanpos.next == null) {
+        jj_lastpos = jj_scanpos = jj_scanpos.next = token_source.getNextToken();
+      } else {
+        jj_lastpos = jj_scanpos = jj_scanpos.next;
+      }
+    } else {
+      jj_scanpos = jj_scanpos.next;
+    }
+    if (jj_rescan) {
+      int i = 0; Token tok = token;
+      while (tok != null && tok != jj_scanpos) { i++; tok = tok.next; }
+      if (tok != null) jj_add_error_token(kind, i);
+    }
+    return (jj_scanpos.kind != kind);
+  }
+
+  final public Token getNextToken() {
+    if (token.next != null) token = token.next;
+    else token = token.next = token_source.getNextToken();
+    jj_ntk = -1;
+    jj_gen++;
+    return token;
+  }
+
+  final public Token getToken(int index) {
+    Token t = lookingAhead ? jj_scanpos : token;
+    for (int i = 0; i < index; i++) {
+      if (t.next != null) t = t.next;
+      else t = t.next = token_source.getNextToken();
+    }
+    return t;
+  }
+
+  final private int jj_ntk() {
+    if ((jj_nt=token.next) == null)
+      return (jj_ntk = (token.next=token_source.getNextToken()).kind);
+    else
+      return (jj_ntk = jj_nt.kind);
+  }
+
+  private java.util.Vector jj_expentries = new java.util.Vector();
+  private int[] jj_expentry;
+  private int jj_kind = -1;
+  private int[] jj_lasttokens = new int[100];
+  private int jj_endpos;
+
+  private void jj_add_error_token(int kind, int pos) {
+    if (pos >= 100) return;
+    if (pos == jj_endpos + 1) {
+      jj_lasttokens[jj_endpos++] = kind;
+    } else if (jj_endpos != 0) {
+      jj_expentry = new int[jj_endpos];
+      for (int i = 0; i < jj_endpos; i++) {
+        jj_expentry[i] = jj_lasttokens[i];
+      }
+      boolean exists = false;
+      for (java.util.Enumeration enum_ = jj_expentries.elements(); enum_.hasMoreElements();) {
+        int[] oldentry = (int[])(enum_.nextElement());
+        if (oldentry.length == jj_expentry.length) {
+          exists = true;
+          for (int i = 0; i < jj_expentry.length; i++) {
+            if (oldentry[i] != jj_expentry[i]) {
+              exists = false;
+              break;
+            }
+          }
+          if (exists) break;
+        }
+      }
+      if (!exists) jj_expentries.addElement(jj_expentry);
+      if (pos != 0) jj_lasttokens[(jj_endpos = pos) - 1] = kind;
+    }
+  }
+
+  final public ParseException generateParseException() {
+    jj_expentries.removeAllElements();
+    boolean[] la1tokens = new boolean[54];
+    for (int i = 0; i < 54; i++) {
+      la1tokens[i] = false;
+    }
+    if (jj_kind >= 0) {
+      la1tokens[jj_kind] = true;
+      jj_kind = -1;
+    }
+    for (int i = 0; i < 34; i++) {
+      if (jj_la1[i] == jj_gen) {
+        for (int j = 0; j < 32; j++) {
+          if ((jj_la1_0[i] & (1<<j)) != 0) {
+            la1tokens[j] = true;
+          }
+          if ((jj_la1_1[i] & (1<<j)) != 0) {
+            la1tokens[32+j] = true;
+          }
+        }
+      }
+    }
+    for (int i = 0; i < 54; i++) {
+      if (la1tokens[i]) {
+        jj_expentry = new int[1];
+        jj_expentry[0] = i;
+        jj_expentries.addElement(jj_expentry);
+      }
+    }
+    jj_endpos = 0;
+    jj_rescan_token();
+    jj_add_error_token(0, 0);
+    int[][] exptokseq = new int[jj_expentries.size()][];
+    for (int i = 0; i < jj_expentries.size(); i++) {
+      exptokseq[i] = (int[])jj_expentries.elementAt(i);
+    }
+    return new ParseException(token, exptokseq, tokenImage);
+  }
+
+  final public void enable_tracing() {
+  }
+
+  final public void disable_tracing() {
+  }
+
+  final private void jj_rescan_token() {
+    jj_rescan = true;
+    for (int i = 0; i < 2; i++) {
+      JJCalls p = jj_2_rtns[i];
+      do {
+        if (p.gen > jj_gen) {
+          jj_la = p.arg; jj_lastpos = jj_scanpos = p.first;
+          switch (i) {
+            case 0: jj_3_1(); break;
+            case 1: jj_3_2(); break;
+          }
+        }
+        p = p.next;
+      } while (p != null);
+    }
+    jj_rescan = false;
+  }
+
+  final private void jj_save(int index, int xla) {
+    JJCalls p = jj_2_rtns[index];
+    while (p.gen > jj_gen) {
+      if (p.next == null) { p = p.next = new JJCalls(); break; }
+      p = p.next;
+    }
+    p.gen = jj_gen + xla - jj_la; p.first = token; p.arg = xla;
+  }
+
+  static final class JJCalls {
+    int gen;
+    Token first;
+    int arg;
+    JJCalls next;
+  }
+
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/parser/ELParserConstants.java b/standard/src/org/apache/taglibs/standard/lang/jstl/parser/ELParserConstants.java
new file mode 100644
index 0000000..c4cd5d2
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/parser/ELParserConstants.java
@@ -0,0 +1,117 @@
+/* Generated By:JavaCC: Do not edit this line. ELParserConstants.java */
+package org.apache.taglibs.standard.lang.jstl.parser;
+
+public interface ELParserConstants {
+
+  int EOF = 0;
+  int NON_EXPRESSION_TEXT = 1;
+  int START_EXPRESSION = 2;
+  int INTEGER_LITERAL = 7;
+  int FLOATING_POINT_LITERAL = 8;
+  int EXPONENT = 9;
+  int STRING_LITERAL = 10;
+  int BADLY_ESCAPED_STRING_LITERAL = 11;
+  int TRUE = 12;
+  int FALSE = 13;
+  int NULL = 14;
+  int END_EXPRESSION = 15;
+  int DOT = 16;
+  int GT1 = 17;
+  int GT2 = 18;
+  int LT1 = 19;
+  int LT2 = 20;
+  int EQ1 = 21;
+  int EQ2 = 22;
+  int LE1 = 23;
+  int LE2 = 24;
+  int GE1 = 25;
+  int GE2 = 26;
+  int NE1 = 27;
+  int NE2 = 28;
+  int LPAREN = 29;
+  int RPAREN = 30;
+  int COMMA = 31;
+  int COLON = 32;
+  int LBRACKET = 33;
+  int RBRACKET = 34;
+  int PLUS = 35;
+  int MINUS = 36;
+  int MULTIPLY = 37;
+  int DIVIDE1 = 38;
+  int DIVIDE2 = 39;
+  int MODULUS1 = 40;
+  int MODULUS2 = 41;
+  int NOT1 = 42;
+  int NOT2 = 43;
+  int AND1 = 44;
+  int AND2 = 45;
+  int OR1 = 46;
+  int OR2 = 47;
+  int EMPTY = 48;
+  int IDENTIFIER = 49;
+  int IMPL_OBJ_START = 50;
+  int LETTER = 51;
+  int DIGIT = 52;
+  int ILLEGAL_CHARACTER = 53;
+
+  int DEFAULT = 0;
+  int IN_EXPRESSION = 1;
+
+  String[] tokenImage = {
+    "<EOF>",
+    "<NON_EXPRESSION_TEXT>",
+    "\"${\"",
+    "\" \"",
+    "\"\\t\"",
+    "\"\\n\"",
+    "\"\\r\"",
+    "<INTEGER_LITERAL>",
+    "<FLOATING_POINT_LITERAL>",
+    "<EXPONENT>",
+    "<STRING_LITERAL>",
+    "<BADLY_ESCAPED_STRING_LITERAL>",
+    "\"true\"",
+    "\"false\"",
+    "\"null\"",
+    "\"}\"",
+    "\".\"",
+    "\">\"",
+    "\"gt\"",
+    "\"<\"",
+    "\"lt\"",
+    "\"==\"",
+    "\"eq\"",
+    "\"<=\"",
+    "\"le\"",
+    "\">=\"",
+    "\"ge\"",
+    "\"!=\"",
+    "\"ne\"",
+    "\"(\"",
+    "\")\"",
+    "\",\"",
+    "\":\"",
+    "\"[\"",
+    "\"]\"",
+    "\"+\"",
+    "\"-\"",
+    "\"*\"",
+    "\"/\"",
+    "\"div\"",
+    "\"%\"",
+    "\"mod\"",
+    "\"not\"",
+    "\"!\"",
+    "\"and\"",
+    "\"&&\"",
+    "\"or\"",
+    "\"||\"",
+    "\"empty\"",
+    "<IDENTIFIER>",
+    "\"#\"",
+    "<LETTER>",
+    "<DIGIT>",
+    "<ILLEGAL_CHARACTER>",
+  };
+
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/parser/ELParserTokenManager.java b/standard/src/org/apache/taglibs/standard/lang/jstl/parser/ELParserTokenManager.java
new file mode 100644
index 0000000..1497c95
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/parser/ELParserTokenManager.java
@@ -0,0 +1,1041 @@
+/* Generated By:JavaCC: Do not edit this line. ELParserTokenManager.java */
+package org.apache.taglibs.standard.lang.jstl.parser;
+
+public class ELParserTokenManager implements ELParserConstants
+{
+  public  java.io.PrintStream debugStream = System.out;
+  public  void setDebugStream(java.io.PrintStream ds) { debugStream = ds; }
+private final int jjStopStringLiteralDfa_0(int pos, long active0)
+{
+   switch (pos)
+   {
+      case 0:
+         if ((active0 & 0x4L) != 0L)
+         {
+            jjmatchedKind = 1;
+            return 2;
+         }
+         return -1;
+      default :
+         return -1;
+   }
+}
+private final int jjStartNfa_0(int pos, long active0)
+{
+   return jjMoveNfa_0(jjStopStringLiteralDfa_0(pos, active0), pos + 1);
+}
+private final int jjStopAtPos(int pos, int kind)
+{
+   jjmatchedKind = kind;
+   jjmatchedPos = pos;
+   return pos + 1;
+}
+private final int jjStartNfaWithStates_0(int pos, int kind, int state)
+{
+   jjmatchedKind = kind;
+   jjmatchedPos = pos;
+   try { curChar = input_stream.readChar(); }
+   catch(java.io.IOException e) { return pos + 1; }
+   return jjMoveNfa_0(state, pos + 1);
+}
+private final int jjMoveStringLiteralDfa0_0()
+{
+   switch(curChar)
+   {
+      case 36:
+         return jjMoveStringLiteralDfa1_0(0x4L);
+      default :
+         return jjMoveNfa_0(1, 0);
+   }
+}
+private final int jjMoveStringLiteralDfa1_0(long active0)
+{
+   try { curChar = input_stream.readChar(); }
+   catch(java.io.IOException e) {
+      jjStopStringLiteralDfa_0(0, active0);
+      return 1;
+   }
+   switch(curChar)
+   {
+      case 123:
+         if ((active0 & 0x4L) != 0L)
+            return jjStopAtPos(1, 2);
+         break;
+      default :
+         break;
+   }
+   return jjStartNfa_0(0, active0);
+}
+private final void jjCheckNAdd(int state)
+{
+   if (jjrounds[state] != jjround)
+   {
+      jjstateSet[jjnewStateCnt++] = state;
+      jjrounds[state] = jjround;
+   }
+}
+private final void jjAddStates(int start, int end)
+{
+   do {
+      jjstateSet[jjnewStateCnt++] = jjnextStates[start];
+   } while (start++ != end);
+}
+private final void jjCheckNAddTwoStates(int state1, int state2)
+{
+   jjCheckNAdd(state1);
+   jjCheckNAdd(state2);
+}
+private final void jjCheckNAddStates(int start, int end)
+{
+   do {
+      jjCheckNAdd(jjnextStates[start]);
+   } while (start++ != end);
+}
+private final void jjCheckNAddStates(int start)
+{
+   jjCheckNAdd(jjnextStates[start]);
+   jjCheckNAdd(jjnextStates[start + 1]);
+}
+static final long[] jjbitVec0 = {
+   0xfffffffffffffffeL, 0xffffffffffffffffL, 0xffffffffffffffffL, 0xffffffffffffffffL
+};
+static final long[] jjbitVec2 = {
+   0x0L, 0x0L, 0xffffffffffffffffL, 0xffffffffffffffffL
+};
+private final int jjMoveNfa_0(int startState, int curPos)
+{
+   int[] nextStates;
+   int startsAt = 0;
+   jjnewStateCnt = 3;
+   int i = 1;
+   jjstateSet[0] = startState;
+   int j, kind = 0x7fffffff;
+   for (;;)
+   {
+      if (++jjround == 0x7fffffff)
+         ReInitRounds();
+      if (curChar < 64)
+      {
+         long l = 1L << curChar;
+         MatchLoop: do
+         {
+            switch(jjstateSet[--i])
+            {
+               case 1:
+                  if ((0xffffffefffffffffL & l) != 0L)
+                  {
+                     if (kind > 1)
+                        kind = 1;
+                     jjCheckNAdd(0);
+                  }
+                  else if (curChar == 36)
+                  {
+                     if (kind > 1)
+                        kind = 1;
+                     jjCheckNAdd(2);
+                  }
+                  break;
+               case 0:
+                  if ((0xffffffefffffffffL & l) == 0L)
+                     break;
+                  if (kind > 1)
+                     kind = 1;
+                  jjCheckNAdd(0);
+                  break;
+               case 2:
+                  if ((0xffffffefffffffffL & l) == 0L)
+                     break;
+                  if (kind > 1)
+                     kind = 1;
+                  jjCheckNAdd(2);
+                  break;
+               default : break;
+            }
+         } while(i != startsAt);
+      }
+      else if (curChar < 128)
+      {
+         long l = 1L << (curChar & 077);
+         MatchLoop: do
+         {
+            switch(jjstateSet[--i])
+            {
+               case 1:
+               case 0:
+                  if (kind > 1)
+                     kind = 1;
+                  jjCheckNAdd(0);
+                  break;
+               case 2:
+                  if ((0xf7ffffffffffffffL & l) == 0L)
+                     break;
+                  if (kind > 1)
+                     kind = 1;
+                  jjstateSet[jjnewStateCnt++] = 2;
+                  break;
+               default : break;
+            }
+         } while(i != startsAt);
+      }
+      else
+      {
+         int hiByte = (int)(curChar >> 8);
+         int i1 = hiByte >> 6;
+         long l1 = 1L << (hiByte & 077);
+         int i2 = (curChar & 0xff) >> 6;
+         long l2 = 1L << (curChar & 077);
+         MatchLoop: do
+         {
+            switch(jjstateSet[--i])
+            {
+               case 1:
+               case 0:
+                  if (!jjCanMove_0(hiByte, i1, i2, l1, l2))
+                     break;
+                  if (kind > 1)
+                     kind = 1;
+                  jjCheckNAdd(0);
+                  break;
+               case 2:
+                  if (!jjCanMove_0(hiByte, i1, i2, l1, l2))
+                     break;
+                  if (kind > 1)
+                     kind = 1;
+                  jjstateSet[jjnewStateCnt++] = 2;
+                  break;
+               default : break;
+            }
+         } while(i != startsAt);
+      }
+      if (kind != 0x7fffffff)
+      {
+         jjmatchedKind = kind;
+         jjmatchedPos = curPos;
+         kind = 0x7fffffff;
+      }
+      ++curPos;
+      if ((i = jjnewStateCnt) == (startsAt = 3 - (jjnewStateCnt = startsAt)))
+         return curPos;
+      try { curChar = input_stream.readChar(); }
+      catch(java.io.IOException e) { return curPos; }
+   }
+}
+private final int jjStopStringLiteralDfa_1(int pos, long active0)
+{
+   switch (pos)
+   {
+      case 0:
+         if ((active0 & 0x1568015547000L) != 0L)
+         {
+            jjmatchedKind = 49;
+            return 6;
+         }
+         if ((active0 & 0x10000L) != 0L)
+            return 1;
+         return -1;
+      case 1:
+         if ((active0 & 0x400015540000L) != 0L)
+            return 6;
+         if ((active0 & 0x1168000007000L) != 0L)
+         {
+            jjmatchedKind = 49;
+            jjmatchedPos = 1;
+            return 6;
+         }
+         return -1;
+      case 2:
+         if ((active0 & 0x168000000000L) != 0L)
+            return 6;
+         if ((active0 & 0x1000000007000L) != 0L)
+         {
+            jjmatchedKind = 49;
+            jjmatchedPos = 2;
+            return 6;
+         }
+         return -1;
+      case 3:
+         if ((active0 & 0x5000L) != 0L)
+            return 6;
+         if ((active0 & 0x1000000002000L) != 0L)
+         {
+            jjmatchedKind = 49;
+            jjmatchedPos = 3;
+            return 6;
+         }
+         return -1;
+      default :
+         return -1;
+   }
+}
+private final int jjStartNfa_1(int pos, long active0)
+{
+   return jjMoveNfa_1(jjStopStringLiteralDfa_1(pos, active0), pos + 1);
+}
+private final int jjStartNfaWithStates_1(int pos, int kind, int state)
+{
+   jjmatchedKind = kind;
+   jjmatchedPos = pos;
+   try { curChar = input_stream.readChar(); }
+   catch(java.io.IOException e) { return pos + 1; }
+   return jjMoveNfa_1(state, pos + 1);
+}
+private final int jjMoveStringLiteralDfa0_1()
+{
+   switch(curChar)
+   {
+      case 33:
+         jjmatchedKind = 43;
+         return jjMoveStringLiteralDfa1_1(0x8000000L);
+      case 37:
+         return jjStopAtPos(0, 40);
+      case 38:
+         return jjMoveStringLiteralDfa1_1(0x200000000000L);
+      case 40:
+         return jjStopAtPos(0, 29);
+      case 41:
+         return jjStopAtPos(0, 30);
+      case 42:
+         return jjStopAtPos(0, 37);
+      case 43:
+         return jjStopAtPos(0, 35);
+      case 44:
+         return jjStopAtPos(0, 31);
+      case 45:
+         return jjStopAtPos(0, 36);
+      case 46:
+         return jjStartNfaWithStates_1(0, 16, 1);
+      case 47:
+         return jjStopAtPos(0, 38);
+      case 58:
+         return jjStopAtPos(0, 32);
+      case 60:
+         jjmatchedKind = 19;
+         return jjMoveStringLiteralDfa1_1(0x800000L);
+      case 61:
+         return jjMoveStringLiteralDfa1_1(0x200000L);
+      case 62:
+         jjmatchedKind = 17;
+         return jjMoveStringLiteralDfa1_1(0x2000000L);
+      case 91:
+         return jjStopAtPos(0, 33);
+      case 93:
+         return jjStopAtPos(0, 34);
+      case 97:
+         return jjMoveStringLiteralDfa1_1(0x100000000000L);
+      case 100:
+         return jjMoveStringLiteralDfa1_1(0x8000000000L);
+      case 101:
+         return jjMoveStringLiteralDfa1_1(0x1000000400000L);
+      case 102:
+         return jjMoveStringLiteralDfa1_1(0x2000L);
+      case 103:
+         return jjMoveStringLiteralDfa1_1(0x4040000L);
+      case 108:
+         return jjMoveStringLiteralDfa1_1(0x1100000L);
+      case 109:
+         return jjMoveStringLiteralDfa1_1(0x20000000000L);
+      case 110:
+         return jjMoveStringLiteralDfa1_1(0x40010004000L);
+      case 111:
+         return jjMoveStringLiteralDfa1_1(0x400000000000L);
+      case 116:
+         return jjMoveStringLiteralDfa1_1(0x1000L);
+      case 124:
+         return jjMoveStringLiteralDfa1_1(0x800000000000L);
+      case 125:
+         return jjStopAtPos(0, 15);
+      default :
+         return jjMoveNfa_1(0, 0);
+   }
+}
+private final int jjMoveStringLiteralDfa1_1(long active0)
+{
+   try { curChar = input_stream.readChar(); }
+   catch(java.io.IOException e) {
+      jjStopStringLiteralDfa_1(0, active0);
+      return 1;
+   }
+   switch(curChar)
+   {
+      case 38:
+         if ((active0 & 0x200000000000L) != 0L)
+            return jjStopAtPos(1, 45);
+         break;
+      case 61:
+         if ((active0 & 0x200000L) != 0L)
+            return jjStopAtPos(1, 21);
+         else if ((active0 & 0x800000L) != 0L)
+            return jjStopAtPos(1, 23);
+         else if ((active0 & 0x2000000L) != 0L)
+            return jjStopAtPos(1, 25);
+         else if ((active0 & 0x8000000L) != 0L)
+            return jjStopAtPos(1, 27);
+         break;
+      case 97:
+         return jjMoveStringLiteralDfa2_1(active0, 0x2000L);
+      case 101:
+         if ((active0 & 0x1000000L) != 0L)
+            return jjStartNfaWithStates_1(1, 24, 6);
+         else if ((active0 & 0x4000000L) != 0L)
+            return jjStartNfaWithStates_1(1, 26, 6);
+         else if ((active0 & 0x10000000L) != 0L)
+            return jjStartNfaWithStates_1(1, 28, 6);
+         break;
+      case 105:
+         return jjMoveStringLiteralDfa2_1(active0, 0x8000000000L);
+      case 109:
+         return jjMoveStringLiteralDfa2_1(active0, 0x1000000000000L);
+      case 110:
+         return jjMoveStringLiteralDfa2_1(active0, 0x100000000000L);
+      case 111:
+         return jjMoveStringLiteralDfa2_1(active0, 0x60000000000L);
+      case 113:
+         if ((active0 & 0x400000L) != 0L)
+            return jjStartNfaWithStates_1(1, 22, 6);
+         break;
+      case 114:
+         if ((active0 & 0x400000000000L) != 0L)
+            return jjStartNfaWithStates_1(1, 46, 6);
+         return jjMoveStringLiteralDfa2_1(active0, 0x1000L);
+      case 116:
+         if ((active0 & 0x40000L) != 0L)
+            return jjStartNfaWithStates_1(1, 18, 6);
+         else if ((active0 & 0x100000L) != 0L)
+            return jjStartNfaWithStates_1(1, 20, 6);
+         break;
+      case 117:
+         return jjMoveStringLiteralDfa2_1(active0, 0x4000L);
+      case 124:
+         if ((active0 & 0x800000000000L) != 0L)
+            return jjStopAtPos(1, 47);
+         break;
+      default :
+         break;
+   }
+   return jjStartNfa_1(0, active0);
+}
+private final int jjMoveStringLiteralDfa2_1(long old0, long active0)
+{
+   if (((active0 &= old0)) == 0L)
+      return jjStartNfa_1(0, old0); 
+   try { curChar = input_stream.readChar(); }
+   catch(java.io.IOException e) {
+      jjStopStringLiteralDfa_1(1, active0);
+      return 2;
+   }
+   switch(curChar)
+   {
+      case 100:
+         if ((active0 & 0x20000000000L) != 0L)
+            return jjStartNfaWithStates_1(2, 41, 6);
+         else if ((active0 & 0x100000000000L) != 0L)
+            return jjStartNfaWithStates_1(2, 44, 6);
+         break;
+      case 108:
+         return jjMoveStringLiteralDfa3_1(active0, 0x6000L);
+      case 112:
+         return jjMoveStringLiteralDfa3_1(active0, 0x1000000000000L);
+      case 116:
+         if ((active0 & 0x40000000000L) != 0L)
+            return jjStartNfaWithStates_1(2, 42, 6);
+         break;
+      case 117:
+         return jjMoveStringLiteralDfa3_1(active0, 0x1000L);
+      case 118:
+         if ((active0 & 0x8000000000L) != 0L)
+            return jjStartNfaWithStates_1(2, 39, 6);
+         break;
+      default :
+         break;
+   }
+   return jjStartNfa_1(1, active0);
+}
+private final int jjMoveStringLiteralDfa3_1(long old0, long active0)
+{
+   if (((active0 &= old0)) == 0L)
+      return jjStartNfa_1(1, old0); 
+   try { curChar = input_stream.readChar(); }
+   catch(java.io.IOException e) {
+      jjStopStringLiteralDfa_1(2, active0);
+      return 3;
+   }
+   switch(curChar)
+   {
+      case 101:
+         if ((active0 & 0x1000L) != 0L)
+            return jjStartNfaWithStates_1(3, 12, 6);
+         break;
+      case 108:
+         if ((active0 & 0x4000L) != 0L)
+            return jjStartNfaWithStates_1(3, 14, 6);
+         break;
+      case 115:
+         return jjMoveStringLiteralDfa4_1(active0, 0x2000L);
+      case 116:
+         return jjMoveStringLiteralDfa4_1(active0, 0x1000000000000L);
+      default :
+         break;
+   }
+   return jjStartNfa_1(2, active0);
+}
+private final int jjMoveStringLiteralDfa4_1(long old0, long active0)
+{
+   if (((active0 &= old0)) == 0L)
+      return jjStartNfa_1(2, old0); 
+   try { curChar = input_stream.readChar(); }
+   catch(java.io.IOException e) {
+      jjStopStringLiteralDfa_1(3, active0);
+      return 4;
+   }
+   switch(curChar)
+   {
+      case 101:
+         if ((active0 & 0x2000L) != 0L)
+            return jjStartNfaWithStates_1(4, 13, 6);
+         break;
+      case 121:
+         if ((active0 & 0x1000000000000L) != 0L)
+            return jjStartNfaWithStates_1(4, 48, 6);
+         break;
+      default :
+         break;
+   }
+   return jjStartNfa_1(3, active0);
+}
+static final long[] jjbitVec3 = {
+   0x1ff00000fffffffeL, 0xffffffffffffc000L, 0xffffffffL, 0x600000000000000L
+};
+static final long[] jjbitVec4 = {
+   0x0L, 0x0L, 0x0L, 0xff7fffffff7fffffL
+};
+static final long[] jjbitVec5 = {
+   0x0L, 0xffffffffffffffffL, 0xffffffffffffffffL, 0xffffffffffffffffL
+};
+static final long[] jjbitVec6 = {
+   0xffffffffffffffffL, 0xffffffffffffffffL, 0xffffL, 0x0L
+};
+static final long[] jjbitVec7 = {
+   0xffffffffffffffffL, 0xffffffffffffffffL, 0x0L, 0x0L
+};
+static final long[] jjbitVec8 = {
+   0x3fffffffffffL, 0x0L, 0x0L, 0x0L
+};
+private final int jjMoveNfa_1(int startState, int curPos)
+{
+   int[] nextStates;
+   int startsAt = 0;
+   jjnewStateCnt = 35;
+   int i = 1;
+   jjstateSet[0] = startState;
+   int j, kind = 0x7fffffff;
+   for (;;)
+   {
+      if (++jjround == 0x7fffffff)
+         ReInitRounds();
+      if (curChar < 64)
+      {
+         long l = 1L << curChar;
+         MatchLoop: do
+         {
+            switch(jjstateSet[--i])
+            {
+               case 0:
+                  if ((0x3ff000000000000L & l) != 0L)
+                  {
+                     if (kind > 7)
+                        kind = 7;
+                     jjCheckNAddStates(0, 4);
+                  }
+                  else if ((0x1800000000L & l) != 0L)
+                  {
+                     if (kind > 49)
+                        kind = 49;
+                     jjCheckNAdd(6);
+                  }
+                  else if (curChar == 39)
+                     jjCheckNAddStates(5, 9);
+                  else if (curChar == 34)
+                     jjCheckNAddStates(10, 14);
+                  else if (curChar == 46)
+                     jjCheckNAdd(1);
+                  break;
+               case 1:
+                  if ((0x3ff000000000000L & l) == 0L)
+                     break;
+                  if (kind > 8)
+                     kind = 8;
+                  jjCheckNAddTwoStates(1, 2);
+                  break;
+               case 3:
+                  if ((0x280000000000L & l) != 0L)
+                     jjCheckNAdd(4);
+                  break;
+               case 4:
+                  if ((0x3ff000000000000L & l) == 0L)
+                     break;
+                  if (kind > 8)
+                     kind = 8;
+                  jjCheckNAdd(4);
+                  break;
+               case 5:
+                  if ((0x1800000000L & l) == 0L)
+                     break;
+                  if (kind > 49)
+                     kind = 49;
+                  jjCheckNAdd(6);
+                  break;
+               case 6:
+                  if ((0x3ff001000000000L & l) == 0L)
+                     break;
+                  if (kind > 49)
+                     kind = 49;
+                  jjCheckNAdd(6);
+                  break;
+               case 7:
+                  if ((0x3ff000000000000L & l) == 0L)
+                     break;
+                  if (kind > 7)
+                     kind = 7;
+                  jjCheckNAddStates(0, 4);
+                  break;
+               case 8:
+                  if ((0x3ff000000000000L & l) == 0L)
+                     break;
+                  if (kind > 7)
+                     kind = 7;
+                  jjCheckNAdd(8);
+                  break;
+               case 9:
+                  if ((0x3ff000000000000L & l) != 0L)
+                     jjCheckNAddTwoStates(9, 10);
+                  break;
+               case 10:
+                  if (curChar != 46)
+                     break;
+                  if (kind > 8)
+                     kind = 8;
+                  jjCheckNAddTwoStates(11, 12);
+                  break;
+               case 11:
+                  if ((0x3ff000000000000L & l) == 0L)
+                     break;
+                  if (kind > 8)
+                     kind = 8;
+                  jjCheckNAddTwoStates(11, 12);
+                  break;
+               case 13:
+                  if ((0x280000000000L & l) != 0L)
+                     jjCheckNAdd(14);
+                  break;
+               case 14:
+                  if ((0x3ff000000000000L & l) == 0L)
+                     break;
+                  if (kind > 8)
+                     kind = 8;
+                  jjCheckNAdd(14);
+                  break;
+               case 15:
+                  if ((0x3ff000000000000L & l) != 0L)
+                     jjCheckNAddTwoStates(15, 16);
+                  break;
+               case 17:
+                  if ((0x280000000000L & l) != 0L)
+                     jjCheckNAdd(18);
+                  break;
+               case 18:
+                  if ((0x3ff000000000000L & l) == 0L)
+                     break;
+                  if (kind > 8)
+                     kind = 8;
+                  jjCheckNAdd(18);
+                  break;
+               case 19:
+                  if (curChar == 34)
+                     jjCheckNAddStates(10, 14);
+                  break;
+               case 20:
+                  if ((0xfffffffbffffffffL & l) != 0L)
+                     jjCheckNAddStates(15, 17);
+                  break;
+               case 22:
+                  if (curChar == 34)
+                     jjCheckNAddStates(15, 17);
+                  break;
+               case 23:
+                  if (curChar == 34 && kind > 10)
+                     kind = 10;
+                  break;
+               case 24:
+                  if ((0xfffffffbffffffffL & l) != 0L)
+                     jjCheckNAddTwoStates(24, 25);
+                  break;
+               case 26:
+                  if ((0xfffffffbffffffffL & l) != 0L && kind > 11)
+                     kind = 11;
+                  break;
+               case 27:
+                  if (curChar == 39)
+                     jjCheckNAddStates(5, 9);
+                  break;
+               case 28:
+                  if ((0xffffff7fffffffffL & l) != 0L)
+                     jjCheckNAddStates(18, 20);
+                  break;
+               case 30:
+                  if (curChar == 39)
+                     jjCheckNAddStates(18, 20);
+                  break;
+               case 31:
+                  if (curChar == 39 && kind > 10)
+                     kind = 10;
+                  break;
+               case 32:
+                  if ((0xffffff7fffffffffL & l) != 0L)
+                     jjCheckNAddTwoStates(32, 33);
+                  break;
+               case 34:
+                  if ((0xffffff7fffffffffL & l) != 0L && kind > 11)
+                     kind = 11;
+                  break;
+               default : break;
+            }
+         } while(i != startsAt);
+      }
+      else if (curChar < 128)
+      {
+         long l = 1L << (curChar & 077);
+         MatchLoop: do
+         {
+            switch(jjstateSet[--i])
+            {
+               case 0:
+               case 6:
+                  if ((0x7fffffe87fffffeL & l) == 0L)
+                     break;
+                  if (kind > 49)
+                     kind = 49;
+                  jjCheckNAdd(6);
+                  break;
+               case 2:
+                  if ((0x2000000020L & l) != 0L)
+                     jjAddStates(21, 22);
+                  break;
+               case 12:
+                  if ((0x2000000020L & l) != 0L)
+                     jjAddStates(23, 24);
+                  break;
+               case 16:
+                  if ((0x2000000020L & l) != 0L)
+                     jjAddStates(25, 26);
+                  break;
+               case 20:
+                  if ((0xffffffffefffffffL & l) != 0L)
+                     jjCheckNAddStates(15, 17);
+                  break;
+               case 21:
+                  if (curChar == 92)
+                     jjstateSet[jjnewStateCnt++] = 22;
+                  break;
+               case 22:
+                  if (curChar == 92)
+                     jjCheckNAddStates(15, 17);
+                  break;
+               case 24:
+                  if ((0xffffffffefffffffL & l) != 0L)
+                     jjAddStates(27, 28);
+                  break;
+               case 25:
+                  if (curChar == 92)
+                     jjstateSet[jjnewStateCnt++] = 26;
+                  break;
+               case 26:
+               case 34:
+                  if ((0xffffffffefffffffL & l) != 0L && kind > 11)
+                     kind = 11;
+                  break;
+               case 28:
+                  if ((0xffffffffefffffffL & l) != 0L)
+                     jjCheckNAddStates(18, 20);
+                  break;
+               case 29:
+                  if (curChar == 92)
+                     jjstateSet[jjnewStateCnt++] = 30;
+                  break;
+               case 30:
+                  if (curChar == 92)
+                     jjCheckNAddStates(18, 20);
+                  break;
+               case 32:
+                  if ((0xffffffffefffffffL & l) != 0L)
+                     jjAddStates(29, 30);
+                  break;
+               case 33:
+                  if (curChar == 92)
+                     jjstateSet[jjnewStateCnt++] = 34;
+                  break;
+               default : break;
+            }
+         } while(i != startsAt);
+      }
+      else
+      {
+         int hiByte = (int)(curChar >> 8);
+         int i1 = hiByte >> 6;
+         long l1 = 1L << (hiByte & 077);
+         int i2 = (curChar & 0xff) >> 6;
+         long l2 = 1L << (curChar & 077);
+         MatchLoop: do
+         {
+            switch(jjstateSet[--i])
+            {
+               case 0:
+               case 6:
+                  if (!jjCanMove_1(hiByte, i1, i2, l1, l2))
+                     break;
+                  if (kind > 49)
+                     kind = 49;
+                  jjCheckNAdd(6);
+                  break;
+               case 20:
+                  if (jjCanMove_0(hiByte, i1, i2, l1, l2))
+                     jjAddStates(15, 17);
+                  break;
+               case 24:
+                  if (jjCanMove_0(hiByte, i1, i2, l1, l2))
+                     jjAddStates(27, 28);
+                  break;
+               case 26:
+               case 34:
+                  if (jjCanMove_0(hiByte, i1, i2, l1, l2) && kind > 11)
+                     kind = 11;
+                  break;
+               case 28:
+                  if (jjCanMove_0(hiByte, i1, i2, l1, l2))
+                     jjAddStates(18, 20);
+                  break;
+               case 32:
+                  if (jjCanMove_0(hiByte, i1, i2, l1, l2))
+                     jjAddStates(29, 30);
+                  break;
+               default : break;
+            }
+         } while(i != startsAt);
+      }
+      if (kind != 0x7fffffff)
+      {
+         jjmatchedKind = kind;
+         jjmatchedPos = curPos;
+         kind = 0x7fffffff;
+      }
+      ++curPos;
+      if ((i = jjnewStateCnt) == (startsAt = 35 - (jjnewStateCnt = startsAt)))
+         return curPos;
+      try { curChar = input_stream.readChar(); }
+      catch(java.io.IOException e) { return curPos; }
+   }
+}
+static final int[] jjnextStates = {
+   8, 9, 10, 15, 16, 28, 29, 31, 32, 33, 20, 21, 23, 24, 25, 20, 
+   21, 23, 28, 29, 31, 3, 4, 13, 14, 17, 18, 24, 25, 32, 33, 
+};
+private static final boolean jjCanMove_0(int hiByte, int i1, int i2, long l1, long l2)
+{
+   switch(hiByte)
+   {
+      case 0:
+         return ((jjbitVec2[i2] & l2) != 0L);
+      default : 
+         if ((jjbitVec0[i1] & l1) != 0L)
+            return true;
+         return false;
+   }
+}
+private static final boolean jjCanMove_1(int hiByte, int i1, int i2, long l1, long l2)
+{
+   switch(hiByte)
+   {
+      case 0:
+         return ((jjbitVec4[i2] & l2) != 0L);
+      case 48:
+         return ((jjbitVec5[i2] & l2) != 0L);
+      case 49:
+         return ((jjbitVec6[i2] & l2) != 0L);
+      case 51:
+         return ((jjbitVec7[i2] & l2) != 0L);
+      case 61:
+         return ((jjbitVec8[i2] & l2) != 0L);
+      default : 
+         if ((jjbitVec3[i1] & l1) != 0L)
+            return true;
+         return false;
+   }
+}
+public static final String[] jjstrLiteralImages = {
+"", null, "\44\173", null, null, null, null, null, null, null, null, null, 
+"\164\162\165\145", "\146\141\154\163\145", "\156\165\154\154", "\175", "\56", "\76", "\147\164", 
+"\74", "\154\164", "\75\75", "\145\161", "\74\75", "\154\145", "\76\75", "\147\145", 
+"\41\75", "\156\145", "\50", "\51", "\54", "\72", "\133", "\135", "\53", "\55", "\52", 
+"\57", "\144\151\166", "\45", "\155\157\144", "\156\157\164", "\41", "\141\156\144", 
+"\46\46", "\157\162", "\174\174", "\145\155\160\164\171", null, null, null, null, null, };
+public static final String[] lexStateNames = {
+   "DEFAULT", 
+   "IN_EXPRESSION", 
+};
+public static final int[] jjnewLexState = {
+   -1, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
+   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
+   -1, -1, -1, -1, 
+};
+static final long[] jjtoToken = {
+   0x23fffffffffd87L, 
+};
+static final long[] jjtoSkip = {
+   0x78L, 
+};
+private SimpleCharStream input_stream;
+private final int[] jjrounds = new int[35];
+private final int[] jjstateSet = new int[70];
+protected char curChar;
+public ELParserTokenManager(SimpleCharStream stream)
+{
+   if (SimpleCharStream.staticFlag)
+      throw new Error("ERROR: Cannot use a static CharStream class with a non-static lexical analyzer.");
+   input_stream = stream;
+}
+public ELParserTokenManager(SimpleCharStream stream, int lexState)
+{
+   this(stream);
+   SwitchTo(lexState);
+}
+public void ReInit(SimpleCharStream stream)
+{
+   jjmatchedPos = jjnewStateCnt = 0;
+   curLexState = defaultLexState;
+   input_stream = stream;
+   ReInitRounds();
+}
+private final void ReInitRounds()
+{
+   int i;
+   jjround = 0x80000001;
+   for (i = 35; i-- > 0;)
+      jjrounds[i] = 0x80000000;
+}
+public void ReInit(SimpleCharStream stream, int lexState)
+{
+   ReInit(stream);
+   SwitchTo(lexState);
+}
+public void SwitchTo(int lexState)
+{
+   if (lexState >= 2 || lexState < 0)
+      throw new TokenMgrError("Error: Ignoring invalid lexical state : " + lexState + ". State unchanged.", TokenMgrError.INVALID_LEXICAL_STATE);
+   else
+      curLexState = lexState;
+}
+
+private final Token jjFillToken()
+{
+   Token t = Token.newToken(jjmatchedKind);
+   t.kind = jjmatchedKind;
+   String im = jjstrLiteralImages[jjmatchedKind];
+   t.image = (im == null) ? input_stream.GetImage() : im;
+   t.beginLine = input_stream.getBeginLine();
+   t.beginColumn = input_stream.getBeginColumn();
+   t.endLine = input_stream.getEndLine();
+   t.endColumn = input_stream.getEndColumn();
+   return t;
+}
+
+int curLexState = 0;
+int defaultLexState = 0;
+int jjnewStateCnt;
+int jjround;
+int jjmatchedPos;
+int jjmatchedKind;
+
+public final Token getNextToken() 
+{
+  int kind;
+  Token specialToken = null;
+  Token matchedToken;
+  int curPos = 0;
+
+  EOFLoop :
+  for (;;)
+  {   
+   try   
+   {     
+      curChar = input_stream.BeginToken();
+   }     
+   catch(java.io.IOException e)
+   {        
+      jjmatchedKind = 0;
+      matchedToken = jjFillToken();
+      return matchedToken;
+   }
+
+   switch(curLexState)
+   {
+     case 0:
+       jjmatchedKind = 0x7fffffff;
+       jjmatchedPos = 0;
+       curPos = jjMoveStringLiteralDfa0_0();
+       break;
+     case 1:
+       try { input_stream.backup(0);
+          while (curChar <= 32 && (0x100002600L & (1L << curChar)) != 0L)
+             curChar = input_stream.BeginToken();
+       }
+       catch (java.io.IOException e1) { continue EOFLoop; }
+       jjmatchedKind = 0x7fffffff;
+       jjmatchedPos = 0;
+       curPos = jjMoveStringLiteralDfa0_1();
+       if (jjmatchedPos == 0 && jjmatchedKind > 53)
+       {
+          jjmatchedKind = 53;
+       }
+       break;
+   }
+     if (jjmatchedKind != 0x7fffffff)
+     {
+        if (jjmatchedPos + 1 < curPos)
+           input_stream.backup(curPos - jjmatchedPos - 1);
+        if ((jjtoToken[jjmatchedKind >> 6] & (1L << (jjmatchedKind & 077))) != 0L)
+        {
+           matchedToken = jjFillToken();
+       if (jjnewLexState[jjmatchedKind] != -1)
+         curLexState = jjnewLexState[jjmatchedKind];
+           return matchedToken;
+        }
+        else
+        {
+         if (jjnewLexState[jjmatchedKind] != -1)
+           curLexState = jjnewLexState[jjmatchedKind];
+           continue EOFLoop;
+        }
+     }
+     int error_line = input_stream.getEndLine();
+     int error_column = input_stream.getEndColumn();
+     String error_after = null;
+     boolean EOFSeen = false;
+     try { input_stream.readChar(); input_stream.backup(1); }
+     catch (java.io.IOException e1) {
+        EOFSeen = true;
+        error_after = curPos <= 1 ? "" : input_stream.GetImage();
+        if (curChar == '\n' || curChar == '\r') {
+           error_line++;
+           error_column = 0;
+        }
+        else
+           error_column++;
+     }
+     if (!EOFSeen) {
+        input_stream.backup(1);
+        error_after = curPos <= 1 ? "" : input_stream.GetImage();
+     }
+     throw new TokenMgrError(EOFSeen, curLexState, error_line, error_column, error_after, curChar, TokenMgrError.LEXICAL_ERROR);
+  }
+}
+
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/parser/ParseException.java b/standard/src/org/apache/taglibs/standard/lang/jstl/parser/ParseException.java
new file mode 100644
index 0000000..0d4e75a
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/parser/ParseException.java
@@ -0,0 +1,192 @@
+/* Generated By:JavaCC: Do not edit this line. ParseException.java Version 2.1 */
+package org.apache.taglibs.standard.lang.jstl.parser;
+
+/**
+ * This exception is thrown when parse errors are encountered.
+ * You can explicitly create objects of this exception type by
+ * calling the method generateParseException in the generated
+ * parser.
+ *
+ * You can modify this class to customize your error reporting
+ * mechanisms so long as you retain the public fields.
+ */
+public class ParseException extends Exception {
+
+  /**
+   * This constructor is used by the method "generateParseException"
+   * in the generated parser.  Calling this constructor generates
+   * a new object of this type with the fields "currentToken",
+   * "expectedTokenSequences", and "tokenImage" set.  The boolean
+   * flag "specialConstructor" is also set to true to indicate that
+   * this constructor was used to create this object.
+   * This constructor calls its super class with the empty string
+   * to force the "toString" method of parent class "Throwable" to
+   * print the error message in the form:
+   *     ParseException: <result of getMessage>
+   */
+  public ParseException(Token currentTokenVal,
+                        int[][] expectedTokenSequencesVal,
+                        String[] tokenImageVal
+                       )
+  {
+    super("");
+    specialConstructor = true;
+    currentToken = currentTokenVal;
+    expectedTokenSequences = expectedTokenSequencesVal;
+    tokenImage = tokenImageVal;
+  }
+
+  /**
+   * The following constructors are for use by you for whatever
+   * purpose you can think of.  Constructing the exception in this
+   * manner makes the exception behave in the normal way - i.e., as
+   * documented in the class "Throwable".  The fields "errorToken",
+   * "expectedTokenSequences", and "tokenImage" do not contain
+   * relevant information.  The JavaCC generated code does not use
+   * these constructors.
+   */
+
+  public ParseException() {
+    super();
+    specialConstructor = false;
+  }
+
+  public ParseException(String message) {
+    super(message);
+    specialConstructor = false;
+  }
+
+  /**
+   * This variable determines which constructor was used to create
+   * this object and thereby affects the semantics of the
+   * "getMessage" method (see below).
+   */
+  protected boolean specialConstructor;
+
+  /**
+   * This is the last token that has been consumed successfully.  If
+   * this object has been created due to a parse error, the token
+   * followng this token will (therefore) be the first error token.
+   */
+  public Token currentToken;
+
+  /**
+   * Each entry in this array is an array of integers.  Each array
+   * of integers represents a sequence of tokens (by their ordinal
+   * values) that is expected at this point of the parse.
+   */
+  public int[][] expectedTokenSequences;
+
+  /**
+   * This is a reference to the "tokenImage" array of the generated
+   * parser within which the parse error occurred.  This array is
+   * defined in the generated ...Constants interface.
+   */
+  public String[] tokenImage;
+
+  /**
+   * This method has the standard behavior when this object has been
+   * created using the standard constructors.  Otherwise, it uses
+   * "currentToken" and "expectedTokenSequences" to generate a parse
+   * error message and returns it.  If this object has been created
+   * due to a parse error, and you do not catch it (it gets thrown
+   * from the parser), then this method is called during the printing
+   * of the final stack trace, and hence the correct error message
+   * gets displayed.
+   */
+  public String getMessage() {
+    if (!specialConstructor) {
+      return super.getMessage();
+    }
+    String expected = "";
+    int maxSize = 0;
+    for (int i = 0; i < expectedTokenSequences.length; i++) {
+      if (maxSize < expectedTokenSequences[i].length) {
+        maxSize = expectedTokenSequences[i].length;
+      }
+      for (int j = 0; j < expectedTokenSequences[i].length; j++) {
+        expected += tokenImage[expectedTokenSequences[i][j]] + " ";
+      }
+      if (expectedTokenSequences[i][expectedTokenSequences[i].length - 1] != 0) {
+        expected += "...";
+      }
+      expected += eol + "    ";
+    }
+    String retval = "Encountered \"";
+    Token tok = currentToken.next;
+    for (int i = 0; i < maxSize; i++) {
+      if (i != 0) retval += " ";
+      if (tok.kind == 0) {
+        retval += tokenImage[0];
+        break;
+      }
+      retval += add_escapes(tok.image);
+      tok = tok.next; 
+    }
+    retval += "\" at line " + currentToken.next.beginLine + ", column " + currentToken.next.beginColumn;
+    retval += "." + eol;
+    if (expectedTokenSequences.length == 1) {
+      retval += "Was expecting:" + eol + "    ";
+    } else {
+      retval += "Was expecting one of:" + eol + "    ";
+    }
+    retval += expected;
+    return retval;
+  }
+
+  /**
+   * The end of line string for this machine.
+   */
+  protected String eol = System.getProperty("line.separator", "\n");
+ 
+  /**
+   * Used to convert raw characters to their escaped version
+   * when these raw version cannot be used as part of an ASCII
+   * string literal.
+   */
+  protected String add_escapes(String str) {
+      StringBuffer retval = new StringBuffer();
+      char ch;
+      for (int i = 0; i < str.length(); i++) {
+        switch (str.charAt(i))
+        {
+           case 0 :
+              continue;
+           case '\b':
+              retval.append("\\b");
+              continue;
+           case '\t':
+              retval.append("\\t");
+              continue;
+           case '\n':
+              retval.append("\\n");
+              continue;
+           case '\f':
+              retval.append("\\f");
+              continue;
+           case '\r':
+              retval.append("\\r");
+              continue;
+           case '\"':
+              retval.append("\\\"");
+              continue;
+           case '\'':
+              retval.append("\\\'");
+              continue;
+           case '\\':
+              retval.append("\\\\");
+              continue;
+           default:
+              if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) {
+                 String s = "0000" + Integer.toString(ch, 16);
+                 retval.append("\\u" + s.substring(s.length() - 4, s.length()));
+              } else {
+                 retval.append(ch);
+              }
+              continue;
+        }
+      }
+      return retval.toString();
+   }
+
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/parser/SimpleCharStream.java b/standard/src/org/apache/taglibs/standard/lang/jstl/parser/SimpleCharStream.java
new file mode 100644
index 0000000..80b36f2
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/parser/SimpleCharStream.java
@@ -0,0 +1,401 @@
+/* Generated By:JavaCC: Do not edit this line. SimpleCharStream.java Version 2.1 */
+package org.apache.taglibs.standard.lang.jstl.parser;
+
+/**
+ * An implementation of interface CharStream, where the stream is assumed to
+ * contain only ASCII characters (without unicode processing).
+ */
+
+public final class SimpleCharStream
+{
+  public static final boolean staticFlag = false;
+  int bufsize;
+  int available;
+  int tokenBegin;
+  public int bufpos = -1;
+  private int bufline[];
+  private int bufcolumn[];
+
+  private int column = 0;
+  private int line = 1;
+
+  private boolean prevCharIsCR = false;
+  private boolean prevCharIsLF = false;
+
+  private java.io.Reader inputStream;
+
+  private char[] buffer;
+  private int maxNextCharInd = 0;
+  private int inBuf = 0;
+
+  private final void ExpandBuff(boolean wrapAround)
+  {
+     char[] newbuffer = new char[bufsize + 2048];
+     int newbufline[] = new int[bufsize + 2048];
+     int newbufcolumn[] = new int[bufsize + 2048];
+
+     try
+     {
+        if (wrapAround)
+        {
+           System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
+           System.arraycopy(buffer, 0, newbuffer,
+                                             bufsize - tokenBegin, bufpos);
+           buffer = newbuffer;
+
+           System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin);
+           System.arraycopy(bufline, 0, newbufline, bufsize - tokenBegin, bufpos);
+           bufline = newbufline;
+
+           System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin);
+           System.arraycopy(bufcolumn, 0, newbufcolumn, bufsize - tokenBegin, bufpos);
+           bufcolumn = newbufcolumn;
+
+           maxNextCharInd = (bufpos += (bufsize - tokenBegin));
+        }
+        else
+        {
+           System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
+           buffer = newbuffer;
+
+           System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin);
+           bufline = newbufline;
+
+           System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin);
+           bufcolumn = newbufcolumn;
+
+           maxNextCharInd = (bufpos -= tokenBegin);
+        }
+     }
+     catch (Throwable t)
+     {
+        throw new Error(t.getMessage());
+     }
+
+
+     bufsize += 2048;
+     available = bufsize;
+     tokenBegin = 0;
+  }
+
+  private final void FillBuff() throws java.io.IOException
+  {
+     if (maxNextCharInd == available)
+     {
+        if (available == bufsize)
+        {
+           if (tokenBegin > 2048)
+           {
+              bufpos = maxNextCharInd = 0;
+              available = tokenBegin;
+           }
+           else if (tokenBegin < 0)
+              bufpos = maxNextCharInd = 0;
+           else
+              ExpandBuff(false);
+        }
+        else if (available > tokenBegin)
+           available = bufsize;
+        else if ((tokenBegin - available) < 2048)
+           ExpandBuff(true);
+        else
+           available = tokenBegin;
+     }
+
+     int i;
+     try {
+        if ((i = inputStream.read(buffer, maxNextCharInd,
+                                    available - maxNextCharInd)) == -1)
+        {
+           inputStream.close();
+           throw new java.io.IOException();
+        }
+        else
+           maxNextCharInd += i;
+        return;
+     }
+     catch(java.io.IOException e) {
+        --bufpos;
+        backup(0);
+        if (tokenBegin == -1)
+           tokenBegin = bufpos;
+        throw e;
+     }
+  }
+
+  public final char BeginToken() throws java.io.IOException
+  {
+     tokenBegin = -1;
+     char c = readChar();
+     tokenBegin = bufpos;
+
+     return c;
+  }
+
+  private final void UpdateLineColumn(char c)
+  {
+     column++;
+
+     if (prevCharIsLF)
+     {
+        prevCharIsLF = false;
+        line += (column = 1);
+     }
+     else if (prevCharIsCR)
+     {
+        prevCharIsCR = false;
+        if (c == '\n')
+        {
+           prevCharIsLF = true;
+        }
+        else
+           line += (column = 1);
+     }
+
+     switch (c)
+     {
+        case '\r' :
+           prevCharIsCR = true;
+           break;
+        case '\n' :
+           prevCharIsLF = true;
+           break;
+        case '\t' :
+           column--;
+           column += (8 - (column & 07));
+           break;
+        default :
+           break;
+     }
+
+     bufline[bufpos] = line;
+     bufcolumn[bufpos] = column;
+  }
+
+  public final char readChar() throws java.io.IOException
+  {
+     if (inBuf > 0)
+     {
+        --inBuf;
+
+        if (++bufpos == bufsize)
+           bufpos = 0;
+
+        return buffer[bufpos];
+     }
+
+     if (++bufpos >= maxNextCharInd)
+        FillBuff();
+
+     char c = buffer[bufpos];
+
+     UpdateLineColumn(c);
+     return (c);
+  }
+
+  /**
+   * @deprecated 
+   * @see #getEndColumn
+   */
+
+  public final int getColumn() {
+     return bufcolumn[bufpos];
+  }
+
+  /**
+   * @deprecated 
+   * @see #getEndLine
+   */
+
+  public final int getLine() {
+     return bufline[bufpos];
+  }
+
+  public final int getEndColumn() {
+     return bufcolumn[bufpos];
+  }
+
+  public final int getEndLine() {
+     return bufline[bufpos];
+  }
+
+  public final int getBeginColumn() {
+     return bufcolumn[tokenBegin];
+  }
+
+  public final int getBeginLine() {
+     return bufline[tokenBegin];
+  }
+
+  public final void backup(int amount) {
+
+    inBuf += amount;
+    if ((bufpos -= amount) < 0)
+       bufpos += bufsize;
+  }
+
+  public SimpleCharStream(java.io.Reader dstream, int startline,
+  int startcolumn, int buffersize)
+  {
+    inputStream = dstream;
+    line = startline;
+    column = startcolumn - 1;
+
+    available = bufsize = buffersize;
+    buffer = new char[buffersize];
+    bufline = new int[buffersize];
+    bufcolumn = new int[buffersize];
+  }
+
+  public SimpleCharStream(java.io.Reader dstream, int startline,
+                                                           int startcolumn)
+  {
+     this(dstream, startline, startcolumn, 4096);
+  }
+
+  public SimpleCharStream(java.io.Reader dstream)
+  {
+     this(dstream, 1, 1, 4096);
+  }
+  public void ReInit(java.io.Reader dstream, int startline,
+  int startcolumn, int buffersize)
+  {
+    inputStream = dstream;
+    line = startline;
+    column = startcolumn - 1;
+
+    if (buffer == null || buffersize != buffer.length)
+    {
+      available = bufsize = buffersize;
+      buffer = new char[buffersize];
+      bufline = new int[buffersize];
+      bufcolumn = new int[buffersize];
+    }
+    prevCharIsLF = prevCharIsCR = false;
+    tokenBegin = inBuf = maxNextCharInd = 0;
+    bufpos = -1;
+  }
+
+  public void ReInit(java.io.Reader dstream, int startline,
+                                                           int startcolumn)
+  {
+     ReInit(dstream, startline, startcolumn, 4096);
+  }
+
+  public void ReInit(java.io.Reader dstream)
+  {
+     ReInit(dstream, 1, 1, 4096);
+  }
+  public SimpleCharStream(java.io.InputStream dstream, int startline,
+  int startcolumn, int buffersize)
+  {
+     this(new java.io.InputStreamReader(dstream), startline, startcolumn, 4096);
+  }
+
+  public SimpleCharStream(java.io.InputStream dstream, int startline,
+                                                           int startcolumn)
+  {
+     this(dstream, startline, startcolumn, 4096);
+  }
+
+  public SimpleCharStream(java.io.InputStream dstream)
+  {
+     this(dstream, 1, 1, 4096);
+  }
+
+  public void ReInit(java.io.InputStream dstream, int startline,
+                          int startcolumn, int buffersize)
+  {
+     ReInit(new java.io.InputStreamReader(dstream), startline, startcolumn, 4096);
+  }
+
+  public void ReInit(java.io.InputStream dstream)
+  {
+     ReInit(dstream, 1, 1, 4096);
+  }
+  public void ReInit(java.io.InputStream dstream, int startline,
+                                                           int startcolumn)
+  {
+     ReInit(dstream, startline, startcolumn, 4096);
+  }
+  public final String GetImage()
+  {
+     if (bufpos >= tokenBegin)
+        return new String(buffer, tokenBegin, bufpos - tokenBegin + 1);
+     else
+        return new String(buffer, tokenBegin, bufsize - tokenBegin) +
+                              new String(buffer, 0, bufpos + 1);
+  }
+
+  public final char[] GetSuffix(int len)
+  {
+     char[] ret = new char[len];
+
+     if ((bufpos + 1) >= len)
+        System.arraycopy(buffer, bufpos - len + 1, ret, 0, len);
+     else
+     {
+        System.arraycopy(buffer, bufsize - (len - bufpos - 1), ret, 0,
+                                                          len - bufpos - 1);
+        System.arraycopy(buffer, 0, ret, len - bufpos - 1, bufpos + 1);
+     }
+
+     return ret;
+  }
+
+  public void Done()
+  {
+     buffer = null;
+     bufline = null;
+     bufcolumn = null;
+  }
+
+  /**
+   * Method to adjust line and column numbers for the start of a token.<BR>
+   */
+  public void adjustBeginLineColumn(int newLine, int newCol)
+  {
+     int start = tokenBegin;
+     int len;
+
+     if (bufpos >= tokenBegin)
+     {
+        len = bufpos - tokenBegin + inBuf + 1;
+     }
+     else
+     {
+        len = bufsize - tokenBegin + bufpos + 1 + inBuf;
+     }
+
+     int i = 0, j = 0, k = 0;
+     int nextColDiff = 0, columnDiff = 0;
+
+     while (i < len &&
+            bufline[j = start % bufsize] == bufline[k = ++start % bufsize])
+     {
+        bufline[j] = newLine;
+        nextColDiff = columnDiff + bufcolumn[k] - bufcolumn[j];
+        bufcolumn[j] = newCol + columnDiff;
+        columnDiff = nextColDiff;
+        i++;
+     } 
+
+     if (i < len)
+     {
+        bufline[j] = newLine++;
+        bufcolumn[j] = newCol + columnDiff;
+
+        while (i++ < len)
+        {
+           if (bufline[j = start % bufsize] != bufline[++start % bufsize])
+              bufline[j] = newLine++;
+           else
+              bufline[j] = newLine;
+        }
+     }
+
+     line = bufline[j];
+     column = bufcolumn[j];
+  }
+
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/parser/Token.java b/standard/src/org/apache/taglibs/standard/lang/jstl/parser/Token.java
new file mode 100644
index 0000000..9f96897
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/parser/Token.java
@@ -0,0 +1,81 @@
+/* Generated By:JavaCC: Do not edit this line. Token.java Version 2.1 */
+package org.apache.taglibs.standard.lang.jstl.parser;
+
+/**
+ * Describes the input token stream.
+ */
+
+public class Token {
+
+  /**
+   * An integer that describes the kind of this token.  This numbering
+   * system is determined by JavaCCParser, and a table of these numbers is
+   * stored in the file ...Constants.java.
+   */
+  public int kind;
+
+  /**
+   * beginLine and beginColumn describe the position of the first character
+   * of this token; endLine and endColumn describe the position of the
+   * last character of this token.
+   */
+  public int beginLine, beginColumn, endLine, endColumn;
+
+  /**
+   * The string image of the token.
+   */
+  public String image;
+
+  /**
+   * A reference to the next regular (non-special) token from the input
+   * stream.  If this is the last token from the input stream, or if the
+   * token manager has not read tokens beyond this one, this field is
+   * set to null.  This is true only if this token is also a regular
+   * token.  Otherwise, see below for a description of the contents of
+   * this field.
+   */
+  public Token next;
+
+  /**
+   * This field is used to access special tokens that occur prior to this
+   * token, but after the immediately preceding regular (non-special) token.
+   * If there are no such special tokens, this field is set to null.
+   * When there are more than one such special token, this field refers
+   * to the last of these special tokens, which in turn refers to the next
+   * previous special token through its specialToken field, and so on
+   * until the first special token (whose specialToken field is null).
+   * The next fields of special tokens refer to other special tokens that
+   * immediately follow it (without an intervening regular token).  If there
+   * is no such token, this field is null.
+   */
+  public Token specialToken;
+
+  /**
+   * Returns the image.
+   */
+  public final String toString()
+  {
+     return image;
+  }
+
+  /**
+   * Returns a new Token object, by default. However, if you want, you
+   * can create and return subclass objects based on the value of ofKind.
+   * Simply add the cases to the switch for all those special cases.
+   * For example, if you have a subclass of Token called IDToken that
+   * you want to create if ofKind is ID, simlpy add something like :
+   *
+   *    case MyParserConstants.ID : return new IDToken();
+   *
+   * to the following switch statement. Then you can cast matchedToken
+   * variable to the appropriate type and use it in your lexical actions.
+   */
+  public static final Token newToken(int ofKind)
+  {
+     switch(ofKind)
+     {
+       default : return new Token();
+     }
+  }
+
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/parser/TokenMgrError.java b/standard/src/org/apache/taglibs/standard/lang/jstl/parser/TokenMgrError.java
new file mode 100644
index 0000000..01ccd35
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/parser/TokenMgrError.java
@@ -0,0 +1,133 @@
+/* Generated By:JavaCC: Do not edit this line. TokenMgrError.java Version 2.1 */
+package org.apache.taglibs.standard.lang.jstl.parser;
+
+public class TokenMgrError extends Error
+{
+   /*
+    * Ordinals for various reasons why an Error of this type can be thrown.
+    */
+
+   /**
+    * Lexical error occured.
+    */
+   static final int LEXICAL_ERROR = 0;
+
+   /**
+    * An attempt wass made to create a second instance of a static token manager.
+    */
+   static final int STATIC_LEXER_ERROR = 1;
+
+   /**
+    * Tried to change to an invalid lexical state.
+    */
+   static final int INVALID_LEXICAL_STATE = 2;
+
+   /**
+    * Detected (and bailed out of) an infinite loop in the token manager.
+    */
+   static final int LOOP_DETECTED = 3;
+
+   /**
+    * Indicates the reason why the exception is thrown. It will have
+    * one of the above 4 values.
+    */
+   int errorCode;
+
+   /**
+    * Replaces unprintable characters by their espaced (or unicode escaped)
+    * equivalents in the given string
+    */
+   protected static final String addEscapes(String str) {
+      StringBuffer retval = new StringBuffer();
+      char ch;
+      for (int i = 0; i < str.length(); i++) {
+        switch (str.charAt(i))
+        {
+           case 0 :
+              continue;
+           case '\b':
+              retval.append("\\b");
+              continue;
+           case '\t':
+              retval.append("\\t");
+              continue;
+           case '\n':
+              retval.append("\\n");
+              continue;
+           case '\f':
+              retval.append("\\f");
+              continue;
+           case '\r':
+              retval.append("\\r");
+              continue;
+           case '\"':
+              retval.append("\\\"");
+              continue;
+           case '\'':
+              retval.append("\\\'");
+              continue;
+           case '\\':
+              retval.append("\\\\");
+              continue;
+           default:
+              if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) {
+                 String s = "0000" + Integer.toString(ch, 16);
+                 retval.append("\\u" + s.substring(s.length() - 4, s.length()));
+              } else {
+                 retval.append(ch);
+              }
+              continue;
+        }
+      }
+      return retval.toString();
+   }
+
+   /**
+    * Returns a detailed message for the Error when it is thrown by the
+    * token manager to indicate a lexical error.
+    * Parameters : 
+    *    EOFSeen     : indicates if EOF caused the lexicl error
+    *    curLexState : lexical state in which this error occured
+    *    errorLine   : line number when the error occured
+    *    errorColumn : column number when the error occured
+    *    errorAfter  : prefix that was seen before this error occured
+    *    curchar     : the offending character
+    * Note: You can customize the lexical error message by modifying this method.
+    */
+   private static final String LexicalError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar) {
+      return("Lexical error at line " +
+           errorLine + ", column " +
+           errorColumn + ".  Encountered: " +
+           (EOFSeen ? "<EOF> " : ("\"" + addEscapes(String.valueOf(curChar)) + "\"") + " (" + (int)curChar + "), ") +
+           "after : \"" + addEscapes(errorAfter) + "\"");
+   }
+
+   /**
+    * You can also modify the body of this method to customize your error messages.
+    * For example, cases like LOOP_DETECTED and INVALID_LEXICAL_STATE are not
+    * of end-users concern, so you can return something like : 
+    *
+    *     "Internal Error : Please file a bug report .... "
+    *
+    * from this method for such cases in the release version of your parser.
+    */
+   public String getMessage() {
+      return super.getMessage();
+   }
+
+   /*
+    * Constructors of various flavors follow.
+    */
+
+   public TokenMgrError() {
+   }
+
+   public TokenMgrError(String message, int reason) {
+      super(message);
+      errorCode = reason;
+   }
+
+   public TokenMgrError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar, int reason) {
+      this(LexicalError(EOFSeen, lexState, errorLine, errorColumn, errorAfter, curChar), reason);
+   }
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/test/Bean1.java b/standard/src/org/apache/taglibs/standard/lang/jstl/test/Bean1.java
new file mode 100644
index 0000000..be2bf68
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/test/Bean1.java
@@ -0,0 +1,276 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl.test;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ *
+ * <p>This is a test bean with a set of properties
+ * 
+ * @author Nathan Abramson - Art Technology Group
+ * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: pierred $
+ **/
+
+public class Bean1
+{
+  //-------------------------------------
+  // Properties
+  //-------------------------------------
+  // property boolean1
+
+  boolean mBoolean1;
+  public boolean getBoolean1 ()
+  { return mBoolean1; }
+  public void setBoolean1 (boolean pBoolean1)
+  { mBoolean1 = pBoolean1; }
+
+  //-------------------------------------
+  // property byte1
+
+  byte mByte1;
+  public byte getByte1 ()
+  { return mByte1; }
+  public void setByte1 (byte pByte1)
+  { mByte1 = pByte1; }
+
+  //-------------------------------------
+  // property char1
+
+  char mChar1;
+  public char getChar1 ()
+  { return mChar1; }
+  public void setChar1 (char pChar1)
+  { mChar1 = pChar1; }
+
+  //-------------------------------------
+  // property short1
+
+  short mShort1;
+  public short getShort1 ()
+  { return mShort1; }
+  public void setShort1 (short pShort1)
+  { mShort1 = pShort1; }
+
+  //-------------------------------------
+  // property int1
+
+  int mInt1;
+  public int getInt1 ()
+  { return mInt1; }
+  public void setInt1 (int pInt1)
+  { mInt1 = pInt1; }
+
+  //-------------------------------------
+  // property long1
+
+  long mLong1;
+  public long getLong1 ()
+  { return mLong1; }
+  public void setLong1 (long pLong1)
+  { mLong1 = pLong1; }
+
+  //-------------------------------------
+  // property float1
+
+  float mFloat1;
+  public float getFloat1 ()
+  { return mFloat1; }
+  public void setFloat1 (float pFloat1)
+  { mFloat1 = pFloat1; }
+
+  //-------------------------------------
+  // property double1
+
+  double mDouble1;
+  public double getDouble1 ()
+  { return mDouble1; }
+  public void setDouble1 (double pDouble1)
+  { mDouble1 = pDouble1; }
+
+  //-------------------------------------
+  // property boolean2
+
+  Boolean mBoolean2;
+  public Boolean getBoolean2 ()
+  { return mBoolean2; }
+  public void setBoolean2 (Boolean pBoolean2)
+  { mBoolean2 = pBoolean2; }
+
+  //-------------------------------------
+  // property byte2
+
+  Byte mByte2;
+  public Byte getByte2 ()
+  { return mByte2; }
+  public void setByte2 (Byte pByte2)
+  { mByte2 = pByte2; }
+
+  //-------------------------------------
+  // property char2
+
+  Character mChar2;
+  public Character getChar2 ()
+  { return mChar2; }
+  public void setChar2 (Character pChar2)
+  { mChar2 = pChar2; }
+
+  //-------------------------------------
+  // property short2
+
+  Short mShort2;
+  public Short getShort2 ()
+  { return mShort2; }
+  public void setShort2 (Short pShort2)
+  { mShort2 = pShort2; }
+
+  //-------------------------------------
+  // property int2
+
+  Integer mInt2;
+  public Integer getInt2 ()
+  { return mInt2; }
+  public void setInt2 (Integer pInt2)
+  { mInt2 = pInt2; }
+
+  //-------------------------------------
+  // property long2
+
+  Long mLong2;
+  public Long getLong2 ()
+  { return mLong2; }
+  public void setLong2 (Long pLong2)
+  { mLong2 = pLong2; }
+
+  //-------------------------------------
+  // property float2
+
+  Float mFloat2;
+  public Float getFloat2 ()
+  { return mFloat2; }
+  public void setFloat2 (Float pFloat2)
+  { mFloat2 = pFloat2; }
+
+  //-------------------------------------
+  // property double2
+
+  Double mDouble2;
+  public Double getDouble2 ()
+  { return mDouble2; }
+  public void setDouble2 (Double pDouble2)
+  { mDouble2 = pDouble2; }
+
+  //-------------------------------------
+  // property string1
+
+  String mString1;
+  public String getString1 ()
+  { return mString1; }
+  public void setString1 (String pString1)
+  { mString1 = pString1; }
+
+  //-------------------------------------
+  // property string2
+
+  String mString2;
+  public String getString2 ()
+  { return mString2; }
+  public void setString2 (String pString2)
+  { mString2 = pString2; }
+
+  //-------------------------------------
+  // property bean1
+
+  Bean1 mBean1;
+  public Bean1 getBean1 ()
+  { return mBean1; }
+  public void setBean1 (Bean1 pBean1)
+  { mBean1 = pBean1; }
+
+  //-------------------------------------
+  // property bean2
+
+  Bean1 mBean2;
+  public Bean1 getBean2 ()
+  { return mBean2; }
+  public void setBean2 (Bean1 pBean2)
+  { mBean2 = pBean2; }
+
+  //-------------------------------------
+  // property noGetter
+
+  String mNoGetter;
+  public void setNoGetter (String pNoGetter)
+  { mNoGetter = pNoGetter; }
+
+  //-------------------------------------
+  // property errorInGetter
+
+  String mErrorInGetter;
+  public String getErrorInGetter ()
+  { throw new NullPointerException ("Error!"); }
+
+  //-------------------------------------
+  // property stringArray1
+
+  String [] mStringArray1;
+  public String [] getStringArray1 ()
+  { return mStringArray1; }
+  public void setStringArray1 (String [] pStringArray1)
+  { mStringArray1 = pStringArray1; }
+
+  //-------------------------------------
+  // property list1
+
+  List mList1;
+  public List getList1 ()
+  { return mList1; }
+  public void setList1 (List pList1)
+  { mList1 = pList1; }
+
+  //-------------------------------------
+  // property map1
+
+  Map mMap1;
+  public Map getMap1 ()
+  { return mMap1; }
+  public void setMap1 (Map pMap1)
+  { mMap1 = pMap1; }
+
+  //-------------------------------------
+  // property indexed1
+
+  public String getIndexed1 (int pIndex)
+  { return mStringArray1 [pIndex]; }
+
+  //-------------------------------------
+  // Member variables
+  //-------------------------------------
+
+  //-------------------------------------
+  /**
+   *
+   * Constructor
+   **/
+  public Bean1 ()
+  {
+  }
+
+  //-------------------------------------
+
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/test/Bean2.java b/standard/src/org/apache/taglibs/standard/lang/jstl/test/Bean2.java
new file mode 100644
index 0000000..2f63207
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/test/Bean2.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl.test;
+
+/**
+ *
+ * <p>This is a test bean that holds a single String
+ * 
+ * @author Nathan Abramson - Art Technology Group
+ * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: pierred $
+ **/
+
+public class Bean2
+{
+  //-------------------------------------
+  // Properties
+  //-------------------------------------
+  // property value
+
+  String mValue;
+  public String getValue ()
+  { return mValue; }
+  public void setValue (String pValue)
+  { mValue = pValue; }
+
+  //-------------------------------------
+  // Member variables
+  //-------------------------------------
+
+  //-------------------------------------
+  /**
+   *
+   * Constructor
+   **/
+  public Bean2 (String pValue)
+  {
+    mValue = pValue;
+  }
+
+  //-------------------------------------
+  public String toString ()
+  {
+    return ("Bean2[" + mValue + "]");
+  }
+
+  //-------------------------------------
+
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/test/Bean2Editor.java b/standard/src/org/apache/taglibs/standard/lang/jstl/test/Bean2Editor.java
new file mode 100644
index 0000000..5647d78
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/test/Bean2Editor.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl.test;
+
+import java.beans.PropertyEditorSupport;
+
+/**
+ *
+ * PropertyEditor for parsing Bean2
+ * 
+ * @author Nathan Abramson - Art Technology Group
+ * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: pierred $
+ **/
+
+public class Bean2Editor
+  extends PropertyEditorSupport
+{
+  //-------------------------------------
+  public void setAsText (String pText)
+    throws IllegalArgumentException
+  {
+    if ("badvalue".equals (pText)) {
+      throw new IllegalArgumentException ("Bad value " + pText);
+    }
+    else {
+      setValue (new Bean2 (pText));
+    }
+  }
+
+  //-------------------------------------
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/test/EvaluationTest.java b/standard/src/org/apache/taglibs/standard/lang/jstl/test/EvaluationTest.java
new file mode 100644
index 0000000..2a13620
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/test/EvaluationTest.java
@@ -0,0 +1,413 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl.test;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.DataInput;
+import java.io.DataInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.PageContext;
+
+import org.apache.taglibs.standard.lang.jstl.Evaluator;
+import org.apache.taglibs.standard.lang.jstl.test.beans.Factory;
+
+/**
+ *
+ * <p>This runs a series of tests specifically for the evaluator.  It
+ * parses and evaluates various expressions in the context of a test
+ * PageContext containing preset data, and prints out the results of
+ * the evaluations.
+ *
+ * <p>The expressions are stored in an input text file, where one line
+ * contains the expression and the next line contains the expected
+ * type.  Blank lines and lines that start with # are ignored.  The
+ * results are written to an output file (blank lines and # lines are
+ * included in the output file).  The output file may be compared
+ * against an existing output file to do regression testing.
+ * 
+ * @author Nathan Abramson - Art Technology Group
+ * @version $Change: 181181 $$DateTime: 2001/06/26 09:55:09 $$Author: pierred $
+ **/
+
+public class EvaluationTest
+{
+  //-------------------------------------
+  // Properties
+  //-------------------------------------
+
+  //-------------------------------------
+  // Member variables
+  //-------------------------------------
+
+  //-------------------------------------
+  /**
+   *
+   * Constructor
+   **/
+  public EvaluationTest ()
+  {
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Runs the tests, reading expressions from pIn and writing the
+   * results to pOut.
+   **/
+  public static void runTests (DataInput pIn,
+			       PrintStream pOut)
+    throws IOException
+  {
+    PageContext context = createTestContext ();
+
+    while (true) {
+      String str = pIn.readLine ();
+      if (str == null) break;
+      if (str.startsWith ("#") ||
+	  "".equals (str.trim ())) {
+	pOut.println (str);
+      }
+      else {
+	String typeStr = pIn.readLine ();
+	pOut.println ("Expression: " + str);
+
+	try {
+	  Class cl = parseClassName (typeStr);
+	  pOut.println ("ExpectedType: " + cl);
+	  Evaluator e = new Evaluator ();
+	  Object val = e.evaluate ("test", str, cl, null, context);
+	  pOut.println ("Evaluates to: " + val);
+	  if (val != null) {
+	    pOut.println ("With type: " + val.getClass ().getName ());
+	  }
+	  pOut.println ();
+	}
+	catch (JspException exc) {
+	  pOut.println ("Causes an error: " + exc);
+	}
+	catch (ClassNotFoundException exc) {
+	  pOut.println ("Causes an error: " + exc);
+	}
+      }
+    }
+
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Finds the class for a class name, including primitive names
+   **/
+  static Class parseClassName (String pClassName)
+    throws ClassNotFoundException
+  {
+    String c = pClassName.trim ();
+    if ("boolean".equals (c)) {
+      return Boolean.TYPE;
+    }
+    else if ("byte".equals (c)) {
+      return Byte.TYPE;
+    }
+    else if ("char".equals (c)) {
+      return Character.TYPE;
+    }
+    else if ("short".equals (c)) {
+      return Short.TYPE;
+    }
+    else if ("int".equals (c)) {
+      return Integer.TYPE;
+    }
+    else if ("long".equals (c)) {
+      return Long.TYPE;
+    }
+    else if ("float".equals (c)) {
+      return Float.TYPE;
+    }
+    else if ("double".equals (c)) {
+      return Double.TYPE;
+    }
+    else {
+      return Class.forName (pClassName);
+    }
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Runs the tests, reading from the given input file and writing to
+   * the given output file.
+   **/
+  public static void runTests (File pInputFile,
+			       File pOutputFile)
+    throws IOException
+  {
+    FileInputStream fin = null;
+    FileOutputStream fout = null;
+    try {
+      fin = new FileInputStream (pInputFile);
+      BufferedInputStream bin = new BufferedInputStream (fin);
+      DataInputStream din = new DataInputStream (bin);
+
+      try {
+	fout = new FileOutputStream (pOutputFile);
+	BufferedOutputStream bout = new BufferedOutputStream (fout);
+	PrintStream pout = new PrintStream (bout);
+
+	runTests (din, pout);
+
+	pout.flush ();
+      }
+      finally {
+	if (fout != null) {
+	  fout.close ();
+	}
+      }
+    }
+    finally {
+      if (fin != null) {
+	fin.close ();
+      }
+    }
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Performs a line-by-line comparison of the two files, returning
+   * true if the files are different, false if not.
+   **/
+  public static boolean isDifferentFiles (DataInput pIn1,
+					  DataInput pIn2)
+    throws IOException
+  {
+    while (true) {
+      String str1 = pIn1.readLine ();
+      String str2 = pIn2.readLine ();
+      if (str1 == null &&
+	  str2 == null) {
+	return false;
+      }
+      else if (str1 == null ||
+	       str2 == null) {
+	return true;
+      }
+      else {
+	if (!str1.equals (str2)) {
+	  return true;
+	}
+      }
+    }
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Performs a line-by-line comparison of the two files, returning
+   * true if the files are different, false if not.
+   **/
+  public static boolean isDifferentFiles (File pFile1,
+					  File pFile2)
+    throws IOException
+  {
+    FileInputStream fin1 = null;
+    try {
+      fin1 = new FileInputStream (pFile1);
+      BufferedInputStream bin1 = new BufferedInputStream (fin1);
+      DataInputStream din1 = new DataInputStream (bin1);
+
+      FileInputStream fin2 = null;
+      try {
+	fin2 = new FileInputStream (pFile2);
+	BufferedInputStream bin2 = new BufferedInputStream (fin2);
+	DataInputStream din2 = new DataInputStream (bin2);
+
+	return isDifferentFiles (din1, din2);
+      }
+      finally {
+	if (fin2 != null) {
+	  fin2.close ();
+	}
+      }
+    }
+    finally {
+      if (fin1 != null) {
+	fin1.close ();
+      }
+    }
+  }
+
+  //-------------------------------------
+  // Test data
+  //-------------------------------------
+  /**
+   *
+   * Creates and returns the test PageContext that will be used for
+   * the tests.
+   **/
+  static PageContext createTestContext ()
+  {
+    PageContext ret = new PageContextImpl ();
+
+    // Create some basic values for lookups
+    ret.setAttribute ("val1a", "page-scoped1", PageContext.PAGE_SCOPE);
+    ret.setAttribute ("val1b", "request-scoped1", PageContext.REQUEST_SCOPE);
+    ret.setAttribute ("val1c", "session-scoped1", PageContext.SESSION_SCOPE);
+    ret.setAttribute ("val1d", "app-scoped1", PageContext.APPLICATION_SCOPE);
+
+    // Create a bean
+    {
+      Bean1 b1 = new Bean1 ();
+      b1.setBoolean1 (true);
+      b1.setByte1 ((byte) 12);
+      b1.setShort1 ((short) -124);
+      b1.setChar1 ('b');
+      b1.setInt1 (4);
+      b1.setLong1 (222423);
+      b1.setFloat1 ((float) 12.4);
+      b1.setDouble1 (89.224);
+      b1.setString1 ("hello");
+      b1.setStringArray1 (new String [] {
+	"string1",
+	"string2",
+	"string3",
+	"string4"
+      });
+      {
+	List l = new ArrayList ();
+	l.add (new Integer (14));
+	l.add ("another value");
+	l.add (b1.getStringArray1 ());
+	b1.setList1 (l);
+      }
+      {
+	Map m = new HashMap ();
+	m.put ("key1", "value1");
+	m.put (new Integer (14), "value2");
+	m.put (new Long (14), "value3");
+	m.put ("recurse", b1);
+	b1.setMap1 (m);
+      }
+      ret.setAttribute ("bean1a", b1);
+
+      Bean1 b2 = new Bean1 ();
+      b2.setInt2 (new Integer (-224));
+      b2.setString2 ("bean2's string");
+      b1.setBean1 (b2);
+
+      Bean1 b3 = new Bean1 ();
+      b3.setDouble1 (1422.332);
+      b3.setString2 ("bean3's string");
+      b2.setBean2 (b3);
+    }
+
+    // Create the public/private beans
+    {
+      ret.setAttribute ("pbean1", Factory.createBean1 ());
+      ret.setAttribute ("pbean2", Factory.createBean2 ());
+      ret.setAttribute ("pbean3", Factory.createBean3 ());
+      ret.setAttribute ("pbean4", Factory.createBean4 ());
+      ret.setAttribute ("pbean5", Factory.createBean5 ());
+      ret.setAttribute ("pbean6", Factory.createBean6 ());
+      ret.setAttribute ("pbean7", Factory.createBean7 ());
+    }
+
+    // Create the empty tests
+    {
+      Map m = new HashMap ();
+      m.put ("emptyArray", new Object [0]);
+      m.put ("nonemptyArray", new Object [] {"abc"});
+      m.put ("emptyList", new ArrayList ());
+      {
+	List l = new ArrayList ();
+	l.add ("hello");
+	m.put ("nonemptyList", l);
+      }
+      m.put ("emptyMap", new HashMap ());
+      {
+	Map m2 = new HashMap ();
+	m2.put ("a", "a");
+	m.put ("nonemptyMap", m2);
+      }
+      m.put ("emptySet", new HashSet ());
+      {
+	Set s = new HashSet ();
+	s.add ("hello");
+	m.put ("nonemptySet", s);
+      }
+      ret.setAttribute ("emptyTests", m);
+    }
+
+    return ret;
+  }
+
+  //-------------------------------------
+  // Main method
+  //-------------------------------------
+  /**
+   *
+   * Runs the evaluation test
+   **/
+  public static void main (String [] pArgs)
+    throws IOException
+  {
+    if (pArgs.length != 2 &&
+	pArgs.length != 3) {
+      usage ();
+      System.exit (1);
+    }
+
+    File in = new File (pArgs [0]);
+    File out = new File (pArgs [1]);
+
+    runTests (in, out);
+
+    if (pArgs.length > 2) {
+      File compare = new File (pArgs [2]);
+      if (isDifferentFiles (out, compare)) {
+	System.out.println ("Test failure - output file " +
+			    out +
+			    " differs from expected output file " +
+			    compare);
+      }
+      else {
+	System.out.println ("tests passed");
+      }
+    }
+  }
+
+  //-------------------------------------
+  static void usage ()
+  {
+    System.err.println ("usage: java org.apache.taglibs.standard.lang.jstl.test.EvaluationTest {input file} {output file} [{compare file}]");
+  }
+
+  //-------------------------------------
+
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/test/PageContextImpl.java b/standard/src/org/apache/taglibs/standard/lang/jstl/test/PageContextImpl.java
new file mode 100644
index 0000000..2cc4860
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/test/PageContextImpl.java
@@ -0,0 +1,301 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl.test;
+
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.servlet.Servlet;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpSession;
+import javax.servlet.jsp.JspWriter;
+import javax.servlet.jsp.PageContext;
+import javax.servlet.jsp.el.ExpressionEvaluator;
+import javax.servlet.jsp.el.VariableResolver;
+
+/**
+ *
+ * <p>This is a "dummy" implementation of PageContext whose only
+ * purpose is to serve the attribute getter/setter API's.
+ * 
+ * @author Nathan Abramson - Art Technology Group
+ * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: pierred $
+ **/
+
+public class PageContextImpl
+  extends PageContext
+{
+  //-------------------------------------
+  // Properties
+  //-------------------------------------
+
+  //-------------------------------------
+  // Member variables
+  //-------------------------------------
+
+  Map mPage = Collections.synchronizedMap (new HashMap ());
+  Map mRequest = Collections.synchronizedMap (new HashMap ());
+  Map mSession = Collections.synchronizedMap (new HashMap ());
+  Map mApp = Collections.synchronizedMap (new HashMap ());
+
+  //-------------------------------------
+  /**
+   *
+   * Constructor
+   **/
+  public PageContextImpl ()
+  {
+  }
+
+  //-------------------------------------
+  // PageContext methods
+  //-------------------------------------
+  public void initialize (Servlet servlet,
+			  ServletRequest request,
+			  ServletResponse response,
+			  String errorPageURL,
+			  boolean needSession,
+			  int bufferSize,
+			  boolean autoFlush)
+  {
+  }
+
+  //-------------------------------------
+  public void release ()
+  {
+  }
+
+  //-------------------------------------
+  public void setAttribute (String name,
+			    Object attribute)
+  {
+    mPage.put (name, attribute);
+  }
+
+  //-------------------------------------
+  public void setAttribute (String name,
+			    Object attribute,
+			    int scope)
+  {
+    switch (scope) {
+    case PAGE_SCOPE:
+      mPage.put (name, attribute);
+      break;
+    case REQUEST_SCOPE:
+      mRequest.put (name, attribute);
+      break;
+    case SESSION_SCOPE:
+      mSession.put (name, attribute);
+      break;
+    case APPLICATION_SCOPE:
+      mApp.put (name, attribute);
+      break;
+    default:
+      throw new IllegalArgumentException  ("Bad scope " + scope);
+    }
+  }
+
+  //-------------------------------------
+  public Object getAttribute (String name)
+  {
+    return mPage.get (name);
+  }
+
+  //-------------------------------------
+  public Object getAttribute (String name,
+			      int scope)
+  {
+    switch (scope) {
+    case PAGE_SCOPE:
+      return mPage.get (name);
+    case REQUEST_SCOPE:
+      return mRequest.get (name);
+    case SESSION_SCOPE:
+      return mSession.get (name);
+    case APPLICATION_SCOPE:
+      return mApp.get (name);
+    default:
+      throw new IllegalArgumentException  ("Bad scope " + scope);
+    }
+  }
+
+  //-------------------------------------
+  public Object findAttribute (String name)
+  {
+    if (mPage.containsKey (name)) {
+      return mPage.get (name);
+    }
+    else if (mRequest.containsKey (name)) {
+      return mRequest.get (name);
+    }
+    else if (mSession.containsKey (name)) {
+      return mSession.get (name);
+    }
+    else if (mApp.containsKey (name)) {
+      return mApp.get (name);
+    }
+    else {
+      return null;
+    }
+  }
+
+  //-------------------------------------
+  public void removeAttribute (String name)
+  {
+    if (mPage.containsKey (name)) {
+      mPage.remove (name);
+    }
+    else if (mRequest.containsKey (name)) {
+      mRequest.remove (name);
+    }
+    else if (mSession.containsKey (name)) {
+      mSession.remove (name);
+    }
+    else if (mApp.containsKey (name)) {
+      mApp.remove (name);
+    }
+  }
+
+  //-------------------------------------
+  public void removeAttribute (String name,
+			       int scope)
+  {
+    switch (scope) {
+    case PAGE_SCOPE:
+      mPage.remove (name);
+      break;
+    case REQUEST_SCOPE:
+      mRequest.remove (name);
+      break;
+    case SESSION_SCOPE:
+      mSession.remove (name);
+      break;
+    case APPLICATION_SCOPE:
+      mApp.remove (name);
+      break;
+    default:
+      throw new IllegalArgumentException  ("Bad scope " + scope);
+    }
+  }
+
+  //-------------------------------------
+  public int getAttributesScope (String name)
+  {
+    if (mPage.containsKey (name)) {
+      return PAGE_SCOPE;
+    }
+    else if (mRequest.containsKey (name)) {
+      return REQUEST_SCOPE;
+    }
+    else if (mSession.containsKey (name)) {
+      return SESSION_SCOPE;
+    }
+    else if (mApp.containsKey (name)) {
+      return APPLICATION_SCOPE;
+    }
+    else {
+      return 0;
+    }
+  }
+
+  //-------------------------------------
+  public Enumeration getAttributeNamesInScope (int scope)
+  {
+    return null;
+  }
+
+  //-------------------------------------
+  public JspWriter getOut ()
+  {
+    return null;
+  }
+
+  //-------------------------------------
+  public HttpSession getSession ()
+  {
+    return null;
+  }
+
+  //-------------------------------------
+  public Object getPage ()
+  {
+    return null;
+  }
+
+  //-------------------------------------
+  public ServletRequest getRequest ()
+  {
+    return null;
+  }
+
+  //-------------------------------------
+  public ServletResponse getResponse ()
+  {
+    return null;
+  }
+
+  //-------------------------------------
+  public Exception getException ()
+  {
+    return null;
+  }
+
+  //-------------------------------------
+  public ServletConfig getServletConfig ()
+  {
+    return null;
+  }
+
+  //-------------------------------------
+  public ServletContext getServletContext ()
+  {
+    return null;
+  }
+
+  //-------------------------------------
+  public void forward (String path)
+  {
+  }
+
+  //-------------------------------------
+  public void include (String path)
+  {
+  }
+
+  //-------------------------------------
+  public void handlePageException (Exception exc)
+  {
+  }
+
+  //-------------------------------------
+  public void handlePageException (Throwable exc)
+  {
+  }
+
+  //-------------------------------------
+  
+  // Since JSP 2.0
+  public void include(java.lang.String relativeUrlPath, boolean flush) {}
+  public ExpressionEvaluator getExpressionEvaluator() { return null; }
+  public VariableResolver getVariableResolver() { return null; }  
+  
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/test/ParserTest.java b/standard/src/org/apache/taglibs/standard/lang/jstl/test/ParserTest.java
new file mode 100644
index 0000000..dff6e41
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/test/ParserTest.java
@@ -0,0 +1,254 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl.test;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.DataInput;
+import java.io.DataInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+
+import javax.servlet.jsp.JspException;
+
+import org.apache.taglibs.standard.lang.jstl.Evaluator;
+
+/**
+ *
+ * <p>This runs a series of tests specifically for the parser.  It
+ * parses various expressions and prints out the canonical
+ * representation of those parsed expressions.
+ *
+ * <p>The expressions are stored in an input text file, with one line
+ * per expression.  Blank lines and lines that start with # are
+ * ignored.  The results are written to an output file (blank lines
+ * and # lines are included in the output file).  The output file may
+ * be compared against an existing output file to do regression
+ * testing.
+ * 
+ * @author Nathan Abramson - Art Technology Group
+ * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: pierred $
+ **/
+
+public class ParserTest
+{
+  //-------------------------------------
+  // Properties
+  //-------------------------------------
+
+  //-------------------------------------
+  // Member variables
+  //-------------------------------------
+
+  //-------------------------------------
+  /**
+   *
+   * Constructor
+   **/
+  public ParserTest ()
+  {
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Runs the tests, reading expressions from pIn and writing the
+   * results to pOut.
+   **/
+  public static void runTests (DataInput pIn,
+			       PrintStream pOut)
+    throws IOException
+  {
+    while (true) {
+      String str = pIn.readLine ();
+      if (str == null) break;
+      if (str.startsWith ("#") ||
+	  "".equals (str.trim ())) {
+	pOut.println (str);
+      }
+      else {
+	// For testing non-ASCII values, the string @@non-ascii gets
+	// converted internally to '\u1111'
+	if ("@@non-ascii".equals (str)) {
+	  str = "\u1111";
+	}
+
+	pOut.println ("Attribute value: " + str);
+	try {
+	  String result = Evaluator.parseAndRender (str);
+	  pOut.println ("Parses to: " + result);
+	}
+	catch (JspException exc) {
+	  pOut.println ("Causes an error: " + exc.getMessage ());
+	}
+      }
+    }
+
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Runs the tests, reading from the given input file and writing to
+   * the given output file.
+   **/
+  public static void runTests (File pInputFile,
+			       File pOutputFile)
+    throws IOException
+  {
+    FileInputStream fin = null;
+    FileOutputStream fout = null;
+    try {
+      fin = new FileInputStream (pInputFile);
+      BufferedInputStream bin = new BufferedInputStream (fin);
+      DataInputStream din = new DataInputStream (bin);
+
+      try {
+	fout = new FileOutputStream (pOutputFile);
+	BufferedOutputStream bout = new BufferedOutputStream (fout);
+	PrintStream pout = new PrintStream (bout);
+
+	runTests (din, pout);
+
+	pout.flush ();
+      }
+      finally {
+	if (fout != null) {
+	  fout.close ();
+	}
+      }
+    }
+    finally {
+      if (fin != null) {
+	fin.close ();
+      }
+    }
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Performs a line-by-line comparison of the two files, returning
+   * true if the files are different, false if not.
+   **/
+  public static boolean isDifferentFiles (DataInput pIn1,
+					  DataInput pIn2)
+    throws IOException
+  {
+    while (true) {
+      String str1 = pIn1.readLine ();
+      String str2 = pIn2.readLine ();
+      if (str1 == null &&
+	  str2 == null) {
+	return false;
+      }
+      else if (str1 == null ||
+	       str2 == null) {
+	return true;
+      }
+      else {
+	if (!str1.equals (str2)) {
+	  return true;
+	}
+      }
+    }
+  }
+
+  //-------------------------------------
+  /**
+   *
+   * Performs a line-by-line comparison of the two files, returning
+   * true if the files are different, false if not.
+   **/
+  public static boolean isDifferentFiles (File pFile1,
+					  File pFile2)
+    throws IOException
+  {
+    FileInputStream fin1 = null;
+    try {
+      fin1 = new FileInputStream (pFile1);
+      BufferedInputStream bin1 = new BufferedInputStream (fin1);
+      DataInputStream din1 = new DataInputStream (bin1);
+
+      FileInputStream fin2 = null;
+      try {
+	fin2 = new FileInputStream (pFile2);
+	BufferedInputStream bin2 = new BufferedInputStream (fin2);
+	DataInputStream din2 = new DataInputStream (bin2);
+
+	return isDifferentFiles (din1, din2);
+      }
+      finally {
+	if (fin2 != null) {
+	  fin2.close ();
+	}
+      }
+    }
+    finally {
+      if (fin1 != null) {
+	fin1.close ();
+      }
+    }
+  }
+
+  //-------------------------------------
+  // Main method
+  //-------------------------------------
+  /**
+   *
+   * Runs the parser test
+   **/
+  public static void main (String [] pArgs)
+    throws IOException
+  {
+    if (pArgs.length != 2 &&
+	pArgs.length != 3) {
+      usage ();
+      System.exit (1);
+    }
+
+    File in = new File (pArgs [0]);
+    File out = new File (pArgs [1]);
+
+    runTests (in, out);
+
+    if (pArgs.length > 2) {
+      File compare = new File (pArgs [2]);
+      if (isDifferentFiles (out, compare)) {
+	System.out.println ("Test failure - output file " +
+			    out +
+			    " differs from expected output file " +
+			    compare);
+      }
+      else {
+	System.out.println ("tests passed");
+      }
+    }
+  }
+
+  //-------------------------------------
+  static void usage ()
+  {
+    System.err.println ("usage: java org.apache.taglibs.standard.lang.jstl.test.ParserTest {input file} {output file} [{compare file}]");
+  }
+
+  //-------------------------------------
+
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/test/StaticFunctionTests.java b/standard/src/org/apache/taglibs/standard/lang/jstl/test/StaticFunctionTests.java
new file mode 100644
index 0000000..b17f3cb
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/test/StaticFunctionTests.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl.test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.taglibs.standard.lang.jstl.Evaluator;
+
+/**
+ *
+ * <p>This class contains some test functions.</p>
+ * 
+ * @author Shawn Bayern
+ */
+
+public class StaticFunctionTests {
+
+  public static void main(String args[]) throws Exception {
+    Map m = getSampleMethodMap();
+    Evaluator e = new Evaluator();
+    Object o;
+    o = e.evaluate("", "4", Integer.class, null, null, m, "foo");
+    System.out.println(o);
+    o = e.evaluate("", "${4}", Integer.class, null, null, m, "foo");
+    System.out.println(o);
+    o = e.evaluate("", "${2+2}", Integer.class, null, null, m, "foo");
+    System.out.println(o);
+    o = e.evaluate("", "${foo:add(2, 3)}", Integer.class, null, null, m, "foo");
+    System.out.println(o);
+    o = e.evaluate("", "${foo:multiply(2, 3)}", Integer.class, null, null, m, "foo");
+    System.out.println(o);
+    o = e.evaluate("", "${add(2, 3)}", Integer.class, null, null, m, "foo");
+    System.out.println(o);
+    o = e.evaluate("", "${multiply(2, 3)}", Integer.class, null, null, m, "foo");
+    System.out.println(o);
+    o = e.evaluate("", "${add(2, 3) + 5}", Integer.class, null, null, m, "foo");
+    System.out.println(o);
+
+    System.out.println("---");
+    o = e.evaluate("", "${getInt(getInteger(getInt(5)))}", Integer.class, null, null, m, "foo");
+    System.out.println(o);
+    o = e.evaluate("", "${getInteger(getInt(getInteger(5)))}", Integer.class, null, null, m, "foo");
+    System.out.println(o);
+    o = e.evaluate("", "${getInt(getInt(getInt(5)))}", Integer.class, null, null, m, "foo");
+    System.out.println(o);
+    o = e.evaluate("", "${getInteger(getInteger(getInteger(5)))}", Integer.class, null, null, m, "foo");
+    System.out.println(o);
+
+  }
+
+  public static int add(int a, int b) {
+    return a + b;
+  }
+
+  public static int multiply(int a, int b) {
+    return a * b;
+  }
+
+  public static int getInt(Integer i) {
+    return i.intValue();
+  }
+
+  public static Integer getInteger(int i) {
+    return new Integer(i);
+  }
+
+  public static Map getSampleMethodMap() throws Exception {
+    Map m = new HashMap();
+    Class c = StaticFunctionTests.class;
+    m.put("foo:add",
+     c.getMethod("add", new Class[] { Integer.TYPE, Integer.TYPE }));
+    m.put("foo:multiply",
+     c.getMethod("multiply", new Class[] { Integer.TYPE, Integer.TYPE }));
+    m.put("foo:getInt",
+     c.getMethod("getInt", new Class[] { Integer.class }));
+    m.put("foo:getInteger",
+     c.getMethod("getInteger", new Class[] { Integer.TYPE }));
+    return m;
+  }
+
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/test/beans/Factory.java b/standard/src/org/apache/taglibs/standard/lang/jstl/test/beans/Factory.java
new file mode 100644
index 0000000..6a3b035
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/test/beans/Factory.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl.test.beans;
+
+/**
+ *
+ * <p>A factory for generating the various beans
+ * 
+ * @author Nathan Abramson - Art Technology Group
+ * @version $Change: 181181 $$DateTime: 2001/06/26 09:55:09 $$Author: pierred $
+ **/
+
+public class Factory
+{
+  public static PublicBean1 createBean1 () 
+  {
+    return new PublicBean1 (); 
+  }
+
+  public static PublicBean1 createBean2 () 
+  {
+    return new PrivateBean1a ();
+  }
+
+  public static PublicBean1 createBean3 () 
+  {
+    return new PublicBean1b ();
+  }
+
+  public static PublicInterface2 createBean4 () 
+  {
+    return new PublicBean2a ();
+  }
+
+  public static PublicInterface2 createBean5 () 
+  {
+    return new PrivateBean2b ();
+  }
+
+  public static PublicInterface2 createBean6 () 
+  {
+    return new PrivateBean2c ();
+  }
+
+  public static PublicInterface2 createBean7 () 
+  {
+    return new PrivateBean2d ();
+  }
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/test/beans/PrivateBean1a.java b/standard/src/org/apache/taglibs/standard/lang/jstl/test/beans/PrivateBean1a.java
new file mode 100644
index 0000000..c7e12d8
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/test/beans/PrivateBean1a.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl.test.beans;
+
+/**
+ *
+ * <p>A private bean subclassing a public bean
+ * 
+ * @author Nathan Abramson - Art Technology Group
+ * @version $Change: 181181 $$DateTime: 2001/06/26 09:55:09 $$Author: pierred $
+ **/
+
+class PrivateBean1a
+  extends PublicBean1
+{
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/test/beans/PrivateBean2b.java b/standard/src/org/apache/taglibs/standard/lang/jstl/test/beans/PrivateBean2b.java
new file mode 100644
index 0000000..ee8c678
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/test/beans/PrivateBean2b.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl.test.beans;
+
+/**
+ *
+ * <p>A private implementation of a public interface
+ * 
+ * @author Nathan Abramson - Art Technology Group
+ * @version $Change: 181181 $$DateTime: 2001/06/26 09:55:09 $$Author: pierred $
+ **/
+
+class PrivateBean2b
+  implements PublicInterface2
+{
+  public Object getValue () { return "got the value"; }
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/test/beans/PrivateBean2c.java b/standard/src/org/apache/taglibs/standard/lang/jstl/test/beans/PrivateBean2c.java
new file mode 100644
index 0000000..eca9f65
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/test/beans/PrivateBean2c.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl.test.beans;
+
+/**
+ *
+ * <p>A private subclass of a public class impelementing a public
+ * interface
+ * 
+ * @author Nathan Abramson - Art Technology Group
+ * @version $Change: 181181 $$DateTime: 2001/06/26 09:55:09 $$Author: pierred $
+ **/
+
+class PrivateBean2c
+  extends PublicBean2a
+{
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/test/beans/PrivateBean2d.java b/standard/src/org/apache/taglibs/standard/lang/jstl/test/beans/PrivateBean2d.java
new file mode 100644
index 0000000..23488e1
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/test/beans/PrivateBean2d.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl.test.beans;
+
+/**
+ *
+ * <p>A private subclass of a private class impelementing a public
+ * interface
+ * 
+ * @author Nathan Abramson - Art Technology Group
+ * @version $Change: 181181 $$DateTime: 2001/06/26 09:55:09 $$Author: pierred $
+ **/
+
+class PrivateBean2d
+  extends PrivateBean2b
+{
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/test/beans/PublicBean1.java b/standard/src/org/apache/taglibs/standard/lang/jstl/test/beans/PublicBean1.java
new file mode 100644
index 0000000..29aa1b2
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/test/beans/PublicBean1.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl.test.beans;
+
+/**
+ *
+ * <p>A publicly-accessible bean
+ * 
+ * @author Nathan Abramson - Art Technology Group
+ * @version $Change: 181181 $$DateTime: 2001/06/26 09:55:09 $$Author: pierred $
+ **/
+
+public class PublicBean1
+{
+  public Object getValue () { return "got the value"; }
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/test/beans/PublicBean1b.java b/standard/src/org/apache/taglibs/standard/lang/jstl/test/beans/PublicBean1b.java
new file mode 100644
index 0000000..326e6e0
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/test/beans/PublicBean1b.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl.test.beans;
+
+/**
+ *
+ * <p>A public bean subclassing a private bean subclassing a public
+ * bean
+ * 
+ * @author Nathan Abramson - Art Technology Group
+ * @version $Change: 181181 $$DateTime: 2001/06/26 09:55:09 $$Author: pierred $
+ **/
+
+public class PublicBean1b
+  extends PrivateBean1a
+{
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/test/beans/PublicBean2a.java b/standard/src/org/apache/taglibs/standard/lang/jstl/test/beans/PublicBean2a.java
new file mode 100644
index 0000000..81c6453
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/test/beans/PublicBean2a.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl.test.beans;
+
+/**
+ *
+ * <p>A publicly-accessible implementation of a public interface
+ * 
+ * @author Nathan Abramson - Art Technology Group
+ * @version $Change: 181181 $$DateTime: 2001/06/26 09:55:09 $$Author: pierred $
+ **/
+
+public class PublicBean2a
+  implements PublicInterface2
+{
+  public Object getValue () { return "got the value"; }
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/test/beans/PublicInterface2.java b/standard/src/org/apache/taglibs/standard/lang/jstl/test/beans/PublicInterface2.java
new file mode 100644
index 0000000..0b3ca79
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/test/beans/PublicInterface2.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.jstl.test.beans;
+
+/**
+ *
+ * <p>A publicly-accessible interface
+ * 
+ * @author Nathan Abramson - Art Technology Group
+ * @version $Change: 181181 $$DateTime: 2001/06/26 09:55:09 $$Author: pierred $
+ **/
+
+public interface PublicInterface2
+{
+  public Object getValue ();
+}
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/test/evaluationTests.txt b/standard/src/org/apache/taglibs/standard/lang/jstl/test/evaluationTests.txt
new file mode 100644
index 0000000..83bbfeb
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/test/evaluationTests.txt
@@ -0,0 +1,1056 @@
+# The set of evaluator tests
+
+#######################################################
+# basic literals
+${1}
+int
+${-12}
+int
+${true}
+boolean
+${false}
+boolean
+${null}
+java.lang.String
+${4.2}
+double
+${-21.3}
+float
+${4.}
+float
+${.21}
+float
+${3e-1}
+double
+${.2222222222}
+double
+
+
+#######################################################
+# basic relationals between literals
+
+${1 < 2}
+boolean
+${1 > 2}
+boolean
+${1 >= 2}
+boolean
+${1 <= 2}
+boolean
+${1 == 2}
+boolean
+${1 != 2}
+boolean
+${3 >= 3}
+boolean
+${3 <= 3}
+boolean
+${3 == 3}
+boolean
+${3 < 3}
+boolean
+${3 > 3}
+boolean
+${3 != 3}
+boolean
+
+
+#######################################################
+# relationals between booleans
+
+${false < true}
+java.lang.Object
+${false > true}
+java.lang.Object
+${true >= true}
+java.lang.Object
+${true <= true}
+java.lang.Object
+${true == true}
+java.lang.Object
+${true != true}
+java.lang.Object
+
+#######################################################
+# looking up objects in scopes
+
+# val1a - defined in page scope
+${pageScope.val1a}
+java.lang.String
+${requestScope.val1a}
+java.lang.String
+${sessionScope.val1a}
+java.lang.String
+${applicationScope.val1a}
+java.lang.String
+${val1a}
+java.lang.String
+
+# val1b - defined in request scope
+${pageScope.val1b}
+java.lang.String
+${requestScope.val1b}
+java.lang.String
+${sessionScope.val1b}
+java.lang.String
+${applicationScope.val1b}
+java.lang.String
+${val1b}
+java.lang.String
+
+# val1c - defined in session scope
+${pageScope.val1c}
+java.lang.String
+${requestScope.val1c}
+java.lang.String
+${sessionScope.val1c}
+java.lang.String
+${applicationScope.val1c}
+java.lang.String
+${val1c}
+java.lang.String
+
+# val1d - defined in application scope
+${pageScope.val1d}
+java.lang.String
+${requestScope.val1d}
+java.lang.String
+${sessionScope.val1d}
+java.lang.String
+${applicationScope.val1d}
+java.lang.String
+${val1d}
+java.lang.String
+
+#######################################################
+# accessing properties
+
+${bean1a.int1}
+int
+${bean1a.boolean1}
+boolean
+${bean1a.string1}
+java.lang.String
+${bean1a.bean1.int2}
+int
+${bean1a.bean1.bean2.string2}
+java.lang.String
+
+#######################################################
+# test the entire conversion matrix
+
+${bean1a.byte1}
+byte
+${bean1a.byte1}
+char
+${bean1a.byte1}
+short
+${bean1a.byte1}
+int
+${bean1a.byte1}
+long
+${bean1a.byte1}
+float
+${bean1a.byte1}
+double
+
+${bean1a.char1}
+byte
+${bean1a.char1}
+char
+${bean1a.char1}
+short
+${bean1a.char1}
+int
+${bean1a.char1}
+long
+${bean1a.char1}
+float
+${bean1a.char1}
+double
+
+${bean1a.short1}
+byte
+${bean1a.short1}
+char
+${bean1a.short1}
+short
+${bean1a.short1}
+int
+${bean1a.short1}
+long
+${bean1a.short1}
+float
+${bean1a.short1}
+double
+
+${bean1a.int1}
+byte
+${bean1a.int1}
+char
+${bean1a.int1}
+short
+${bean1a.int1}
+int
+${bean1a.int1}
+long
+${bean1a.int1}
+float
+${bean1a.int1}
+double
+
+${bean1a.long1}
+byte
+${bean1a.long1}
+char
+${bean1a.long1}
+short
+${bean1a.long1}
+int
+${bean1a.long1}
+long
+${bean1a.long1}
+float
+${bean1a.long1}
+double
+
+${bean1a.float1}
+byte
+${bean1a.float1}
+char
+${bean1a.float1}
+short
+${bean1a.float1}
+int
+${bean1a.float1}
+long
+${bean1a.float1}
+float
+${bean1a.float1}
+double
+
+${bean1a.double1}
+byte
+${bean1a.double1}
+char
+${bean1a.double1}
+short
+${bean1a.double1}
+int
+${bean1a.double1}
+long
+${bean1a.double1}
+float
+${bean1a.double1}
+double
+
+#######################################################
+# test the entire relational comparison type promotion matrix
+
+${bean1a.byte1 < bean1a.byte1}
+boolean
+${bean1a.byte1 < bean1a.char1}
+boolean
+${bean1a.byte1 < bean1a.short1}
+boolean
+${bean1a.byte1 < bean1a.int1}
+boolean
+${bean1a.byte1 < bean1a.long1}
+boolean
+${bean1a.byte1 < bean1a.float1}
+boolean
+${bean1a.byte1 < bean1a.double1}
+boolean
+
+${bean1a.char1 < bean1a.byte1}
+boolean
+${bean1a.char1 < bean1a.char1}
+boolean
+${bean1a.char1 < bean1a.short1}
+boolean
+${bean1a.char1 < bean1a.int1}
+boolean
+${bean1a.char1 < bean1a.long1}
+boolean
+${bean1a.char1 < bean1a.float1}
+boolean
+${bean1a.char1 < bean1a.double1}
+boolean
+
+${bean1a.short1 < bean1a.byte1}
+boolean
+${bean1a.short1 < bean1a.char1}
+boolean
+${bean1a.short1 < bean1a.short1}
+boolean
+${bean1a.short1 < bean1a.int1}
+boolean
+${bean1a.short1 < bean1a.long1}
+boolean
+${bean1a.short1 < bean1a.float1}
+boolean
+${bean1a.short1 < bean1a.double1}
+boolean
+
+${bean1a.int1 < bean1a.byte1}
+boolean
+${bean1a.int1 < bean1a.char1}
+boolean
+${bean1a.int1 < bean1a.short1}
+boolean
+${bean1a.int1 < bean1a.int1}
+boolean
+${bean1a.int1 < bean1a.long1}
+boolean
+${bean1a.int1 < bean1a.float1}
+boolean
+${bean1a.int1 < bean1a.double1}
+boolean
+
+${bean1a.long1 < bean1a.byte1}
+boolean
+${bean1a.long1 < bean1a.char1}
+boolean
+${bean1a.long1 < bean1a.short1}
+boolean
+${bean1a.long1 < bean1a.int1}
+boolean
+${bean1a.long1 < bean1a.long1}
+boolean
+${bean1a.long1 < bean1a.float1}
+boolean
+${bean1a.long1 < bean1a.double1}
+boolean
+
+${bean1a.float1 < bean1a.byte1}
+boolean
+${bean1a.float1 < bean1a.char1}
+boolean
+${bean1a.float1 < bean1a.short1}
+boolean
+${bean1a.float1 < bean1a.int1}
+boolean
+${bean1a.float1 < bean1a.long1}
+boolean
+${bean1a.float1 < bean1a.float1}
+boolean
+${bean1a.float1 < bean1a.double1}
+boolean
+
+${bean1a.double1 < bean1a.byte1}
+boolean
+${bean1a.double1 < bean1a.char1}
+boolean
+${bean1a.double1 < bean1a.short1}
+boolean
+${bean1a.double1 < bean1a.int1}
+boolean
+${bean1a.double1 < bean1a.long1}
+boolean
+${bean1a.double1 < bean1a.float1}
+boolean
+${bean1a.double1 < bean1a.double1}
+boolean
+
+#######################################################
+# test other relational comparison rules
+
+${null == null}
+boolean
+${noSuchAttribute == noSuchAttribute}
+boolean
+${noSuchAttribute == null}
+boolean
+${null == noSuchAttribute}
+boolean
+${bean1a == null}
+boolean
+${null == bean1a}
+boolean
+${bean1a == bean1a}
+boolean
+${bean1a > "hello"}
+boolean
+${bean1a.bean1 < 14}
+boolean
+${bean1a.bean1 == "hello"}
+boolean
+
+#######################################################
+# test String comparisons
+
+${bean1a.string1 == "hello"}
+boolean
+${bean1a.string1 != "hello"}
+boolean
+${bean1a.string1 == "goodbye"}
+boolean
+${bean1a.string1 != "goodbye"}
+boolean
+${bean1a.string1 > "goodbye"}
+boolean
+${"hello" == bean1a.string1}
+boolean
+${"goodbye" > bean1a.string1}
+boolean
+
+#######################################################
+# test errors in property traversal
+
+${noSuchAttribute.abc}
+java.lang.Object
+${bean1a.bean2.byte1}
+java.lang.Object
+${bean1a.noProperty}
+java.lang.Object
+${bean1a.noGetter}
+java.lang.Object
+${bean1a.errorInGetter}
+java.lang.Object
+${bean1a.bean2.string2}
+java.lang.Object
+
+#######################################################
+# test accessing public properties from private classes
+
+${pbean1.value}
+java.lang.Object
+${pbean2.value}
+java.lang.Object
+${pbean3.value}
+java.lang.Object
+${pbean4.value}
+java.lang.Object
+${pbean5.value}
+java.lang.Object
+${pbean6.value}
+java.lang.Object
+${pbean7.value}
+java.lang.Object
+
+#######################################################
+# test literal conversions
+
+true
+boolean
+false
+boolean
+12
+byte
+12
+char
+12
+short
+12
+int
+12
+long
+12
+float
+12
+double
+
+hello
+org.apache.taglibs.standard.lang.jstl.test.Bean2
+badvalue
+org.apache.taglibs.standard.lang.jstl.test.Bean2
+hello
+org.apache.taglibs.standard.lang.jstl.test.Bean1
+
+#######################################################
+# test null values bumped up to constants
+
+${null}
+boolean
+${null}
+byte
+${null}
+short
+${null}
+char
+${null}
+int
+${null}
+long
+${null}
+float
+${null}
+double
+${null}
+java.lang.Boolean
+${null}
+java.lang.Byte
+${null}
+java.lang.Short
+${null}
+java.lang.Character
+${null}
+java.lang.Integer
+${null}
+java.lang.Long
+${null}
+java.lang.Float
+${null}
+java.lang.Double
+
+
+#######################################################
+# test reserved words as identifiers
+
+${and}
+java.lang.Object
+${or}
+java.lang.Object
+${not}
+java.lang.Object
+${eq}
+java.lang.Object
+${ne}
+java.lang.Object
+${lt}
+java.lang.Object
+${gt}
+java.lang.Object
+${le}
+java.lang.Object
+${ge}
+java.lang.Object
+${instanceof}
+java.lang.Object
+${true}
+java.lang.Object
+${false}
+java.lang.Object
+${null}
+java.lang.Object
+
+
+#######################################################
+# test reserved words as property names
+
+${bean1a.and}
+java.lang.Object
+${bean1a.or}
+java.lang.Object
+${bean1a.not}
+java.lang.Object
+${bean1a.eq}
+java.lang.Object
+${bean1a.ne}
+java.lang.Object
+${bean1a.lt}
+java.lang.Object
+${bean1a.gt}
+java.lang.Object
+${bean1a.le}
+java.lang.Object
+${bean1a.ge}
+java.lang.Object
+${bean1a.instanceof}
+java.lang.Object
+${bean1a.page}
+java.lang.Object
+${bean1a.request}
+java.lang.Object
+${bean1a.session}
+java.lang.Object
+${bean1a.application}
+java.lang.Object
+${bean1a.true}
+java.lang.Object
+${bean1a.false}
+java.lang.Object
+${bean1a.null}
+java.lang.Object
+
+#######################################################
+# test arithmetic
+
+${3+5}
+java.lang.Object
+${3-5}
+java.lang.Object
+${3/5}
+java.lang.Object
+${3*5}
+java.lang.Object
+${3*5.0}
+java.lang.Object
+${3.0*5}
+java.lang.Object
+${3.0*5.0}
+java.lang.Object
+${225 % 17}
+java.lang.Object
+
+${ 1 + 2 + 3 * 5 + 6}
+java.lang.Object
+${ 1 + (2 + 3) * 5 + 6}
+java.lang.Object
+
+#######################################################
+# test logical operators
+
+${ true}
+java.lang.Object
+${ not true}
+java.lang.Object
+${ not false}
+java.lang.Object
+${ not not true}
+java.lang.Object
+${ not not false}
+java.lang.Object
+${ true and false}
+java.lang.Object
+${ true and true}
+java.lang.Object
+${ false and true}
+java.lang.Object
+${ false and false}
+java.lang.Object
+${ true or false}
+java.lang.Object
+${ true or true}
+java.lang.Object
+${ false or true}
+java.lang.Object
+${ false or false}
+java.lang.Object
+
+${ false or false or false or true and false}
+java.lang.Object
+${ false or false or false or true and false or true}
+java.lang.Object
+
+#######################################################
+# test indexed access operator
+
+# Test as equivalent to property accessor
+${ bean1a["double1"] }
+java.lang.Object
+${ bean1a["double1"].class }
+java.lang.Object
+
+# Test as array accessor
+${ bean1a.stringArray1[-1]}
+java.lang.Object
+${ bean1a.stringArray1[0]}
+java.lang.Object
+${ bean1a.stringArray1[1]}
+java.lang.Object
+${ bean1a.stringArray1[2]}
+java.lang.Object
+${ bean1a.stringArray1[3]}
+java.lang.Object
+${ bean1a.stringArray1[4]}
+java.lang.Object
+
+# Test as list accessor
+${ bean1a.list1 [0] }
+java.lang.Object
+${ bean1a.list1 [1] }
+java.lang.Object
+${ bean1a.list1 [2][2] }
+java.lang.Object
+
+# Test as indexed property accessor
+${ bean1a.indexed1[-1]}
+java.lang.Object
+${ bean1a.indexed1[0]}
+java.lang.Object
+${ bean1a.indexed1[1]}
+java.lang.Object
+${ bean1a.indexed1[2]}
+java.lang.Object
+${ bean1a.indexed1[3]}
+java.lang.Object
+${ bean1a.indexed1[4]}
+java.lang.Object
+
+# Test as map accessor
+${ bean1a.map1.key1 }
+java.lang.Object
+${ bean1a.map1 ["key1"] }
+java.lang.Object
+${ bean1a.map1 [14] }
+java.lang.Object
+${ bean1a.map1 [2 * 7] }
+java.lang.Object
+${ bean1a.map1.recurse.list1[0] }
+java.lang.Object
+
+#######################################################
+# test String concatenation
+
+${ "a" + "bcd" }
+java.lang.Object
+${ "a" + (4*3) }
+java.lang.Object
+${ bean1a.map1 ["key" + (5-4)] }
+java.lang.Object
+
+#######################################################
+# test String comparisons
+
+${ "30" < "4" }
+java.lang.Object
+${ 30 < "4" }
+java.lang.Object
+${ 30 > "4" }
+java.lang.Object
+${ "0004" == "4" }
+java.lang.Object
+
+#######################################################
+# test relational comparison with alternate symbols
+
+${ 4 eq 3}
+java.lang.Object
+${ 4 ne 3}
+java.lang.Object
+${ 4 eq 4}
+java.lang.Object
+${ 4 ne 4}
+java.lang.Object
+${ 4 lt 3}
+java.lang.Object
+${ 4 gt 3}
+java.lang.Object
+${ 4 le 3}
+java.lang.Object
+${ 4 ge 3}
+java.lang.Object
+${ 4 le 4}
+java.lang.Object
+${ 4 ge 4}
+java.lang.Object
+
+#######################################################
+# test expressions on the left side of a value suffix
+
+${(3).class}
+java.lang.Object
+${(bean1a.map1)["key1"]}
+java.lang.Object
+
+
+#######################################################
+# test String/boolean logical operators
+
+${'true' and false}
+java.lang.Object
+${'true' or true}
+java.lang.Object
+${false and 'true'}
+java.lang.Object
+${false or 'true'}
+java.lang.Object
+
+#######################################################
+# test empty operator
+
+${ empty "A"}
+java.lang.Object
+${ empty "" }
+java.lang.Object
+${ empty null }
+java.lang.Object
+${ empty false}
+java.lang.Object
+${ empty 0}
+java.lang.Object
+${ not empty 0}
+java.lang.Object
+${ not empty empty 0}
+java.lang.Object
+${ empty emptyTests.emptyArray }
+java.lang.Object
+${ empty emptyTests.nonemptyArray }
+java.lang.Object
+${ empty emptyTests.emptyList }
+java.lang.Object
+${ empty emptyTests.nonemptyList }
+java.lang.Object
+${ empty emptyTests.emptyMap }
+java.lang.Object
+${ empty emptyTests.nonemptyMap }
+java.lang.Object
+${ empty emptyTests.emptySet }
+java.lang.Object
+${ empty emptyTests.nonemptySet }
+java.lang.Object
+
+#######################################################
+# test String arithmetic
+
+${ "6" / "3" }
+java.lang.Object
+${ 3 + "4" }
+java.lang.Object
+${ "4" + 3 }
+java.lang.Object
+${ 3 + "4.5" }
+java.lang.Object
+${ "4.5" + 3 }
+java.lang.Object
+${ 3.0 + 6.0}
+java.lang.Object
+${ 31121.0 * 61553.0 }
+java.lang.Object
+${ 31121 * 61553 }
+java.lang.Object
+${ 65536 * 65536 * 65536 * 32759 }
+java.lang.Object
+${ 9220838762064379904.0 - 9220838762064379900.0 }
+java.lang.Object
+${ 9220838762064379904 - 9220838762064379900 }
+java.lang.Object
+
+#######################################################
+# test relational operators involving null
+
+${ null == null }
+java.lang.Object
+${ null != null }
+java.lang.Object
+${ null > null }
+java.lang.Object
+${ null < null }
+java.lang.Object
+${ null >= null }
+java.lang.Object
+${ null <= null }
+java.lang.Object
+
+${ null == 3 }
+java.lang.Object
+${ null != 3 }
+java.lang.Object
+${ null > 3 }
+java.lang.Object
+${ null < 3 }
+java.lang.Object
+${ null >= 3 }
+java.lang.Object
+${ null <= 3 }
+java.lang.Object
+
+${ 3 == null }
+java.lang.Object
+${ 3 != null }
+java.lang.Object
+${ 3 > null }
+java.lang.Object
+${ 3 < null }
+java.lang.Object
+${ 3 >= null }
+java.lang.Object
+${ 3 <= null }
+java.lang.Object
+
+${ null == "" }
+java.lang.Object
+${ null != "" }
+java.lang.Object
+${ "" == null }
+java.lang.Object
+${ "" != null }
+java.lang.Object
+
+#######################################################
+# arithmetic operators involving Strings
+
+${ 4 + 3 }
+java.lang.Object
+${ 4.0 + 3 }
+java.lang.Object
+${ 4 + 3.0 }
+java.lang.Object
+${ 4.0 + 3.0 }
+java.lang.Object
+${ "4" + 3 }
+java.lang.Object
+${ "4.0" + 3 }
+java.lang.Object
+${ "4" + 3.0 }
+java.lang.Object
+${ "4.0" + 3.0 }
+java.lang.Object
+${ 4 + "3" }
+java.lang.Object
+${ 4.0 + "3" }
+java.lang.Object
+${ 4 + "3.0" }
+java.lang.Object
+${ 4.0 + "3.0" }
+java.lang.Object
+${ "4" + "3" }
+java.lang.Object
+${ "4.0" + "3" }
+java.lang.Object
+${ "4" + "3.0" }
+java.lang.Object
+${ "4.0" + "3.0" }
+java.lang.Object
+
+
+${ 4 - 3 }
+java.lang.Object
+${ 4.0 - 3 }
+java.lang.Object
+${ 4 - 3.0 }
+java.lang.Object
+${ 4.0 - 3.0 }
+java.lang.Object
+${ "4" - 3 }
+java.lang.Object
+${ "4.0" - 3 }
+java.lang.Object
+${ "4" - 3.0 }
+java.lang.Object
+${ "4.0" - 3.0 }
+java.lang.Object
+${ 4 - "3" }
+java.lang.Object
+${ 4.0 - "3" }
+java.lang.Object
+${ 4 - "3.0" }
+java.lang.Object
+${ 4.0 - "3.0" }
+java.lang.Object
+${ "4" - "3" }
+java.lang.Object
+${ "4.0" - "3" }
+java.lang.Object
+${ "4" - "3.0" }
+java.lang.Object
+${ "4.0" - "3.0" }
+java.lang.Object
+
+
+${ 4 * 3 }
+java.lang.Object
+${ 4.0 * 3 }
+java.lang.Object
+${ 4 * 3.0 }
+java.lang.Object
+${ 4.0 * 3.0 }
+java.lang.Object
+${ "4" * 3 }
+java.lang.Object
+${ "4.0" * 3 }
+java.lang.Object
+${ "4" * 3.0 }
+java.lang.Object
+${ "4.0" * 3.0 }
+java.lang.Object
+${ 4 * "3" }
+java.lang.Object
+${ 4.0 * "3" }
+java.lang.Object
+${ 4 * "3.0" }
+java.lang.Object
+${ 4.0 * "3.0" }
+java.lang.Object
+${ "4" * "3" }
+java.lang.Object
+${ "4.0" * "3" }
+java.lang.Object
+${ "4" * "3.0" }
+java.lang.Object
+${ "4.0" * "3.0" }
+java.lang.Object
+
+
+${ 4 / 3 }
+java.lang.Object
+${ 4.0 / 3 }
+java.lang.Object
+${ 4 / 3.0 }
+java.lang.Object
+${ 4.0 / 3.0 }
+java.lang.Object
+${ "4" / 3 }
+java.lang.Object
+${ "4.0" / 3 }
+java.lang.Object
+${ "4" / 3.0 }
+java.lang.Object
+${ "4.0" / 3.0 }
+java.lang.Object
+${ 4 / "3" }
+java.lang.Object
+${ 4.0 / "3" }
+java.lang.Object
+${ 4 / "3.0" }
+java.lang.Object
+${ 4.0 / "3.0" }
+java.lang.Object
+${ "4" / "3" }
+java.lang.Object
+${ "4.0" / "3" }
+java.lang.Object
+${ "4" / "3.0" }
+java.lang.Object
+${ "4.0" / "3.0" }
+java.lang.Object
+
+
+${ 4 % 3 }
+java.lang.Object
+${ 4.0 % 3 }
+java.lang.Object
+${ 4 % 3.0 }
+java.lang.Object
+${ 4.0 % 3.0 }
+java.lang.Object
+${ "4" % 3 }
+java.lang.Object
+${ "4.0" % 3 }
+java.lang.Object
+${ "4" % 3.0 }
+java.lang.Object
+${ "4.0" % 3.0 }
+java.lang.Object
+${ 4 % "3" }
+java.lang.Object
+${ 4.0 % "3" }
+java.lang.Object
+${ 4 % "3.0" }
+java.lang.Object
+${ 4.0 % "3.0" }
+java.lang.Object
+${ "4" % "3" }
+java.lang.Object
+${ "4.0" % "3" }
+java.lang.Object
+${ "4" % "3.0" }
+java.lang.Object
+${ "4.0" % "3.0" }
+java.lang.Object
+
+
+${ "8" / "2" }
+java.lang.Object
+${ "4e2" + "3" }
+java.lang.Object
+${ "4" + "3e2" }
+java.lang.Object
+${ "4e2" + "3e2" }
+java.lang.Object
+
+
+#######################################################
+# unary minus operator involving Strings
+
+${ -3 }
+java.lang.Object
+${ -3.0 }
+java.lang.Object
+${ -"3" }
+java.lang.Object
+${ -"3.0" }
+java.lang.Object
+${ -"3e2" }
+java.lang.Object
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/test/evaluationTestsOutput.txt b/standard/src/org/apache/taglibs/standard/lang/jstl/test/evaluationTestsOutput.txt
new file mode 100644
index 0000000..02420eb
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/test/evaluationTestsOutput.txt
@@ -0,0 +1,2390 @@
+# The set of evaluator tests
+
+#######################################################
+# basic literals
+Expression: ${1}
+ExpectedType: int
+Evaluates to: 1
+With type: java.lang.Integer
+
+Expression: ${-12}
+ExpectedType: int
+Evaluates to: -12
+With type: java.lang.Integer
+
+Expression: ${true}
+ExpectedType: boolean
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: ${false}
+ExpectedType: boolean
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${null}
+ExpectedType: class java.lang.String
+Evaluates to: 
+With type: java.lang.String
+
+Expression: ${4.2}
+ExpectedType: double
+Evaluates to: 4.2
+With type: java.lang.Double
+
+Expression: ${-21.3}
+ExpectedType: float
+Evaluates to: -21.3
+With type: java.lang.Float
+
+Expression: ${4.}
+ExpectedType: float
+Evaluates to: 4.0
+With type: java.lang.Float
+
+Expression: ${.21}
+ExpectedType: float
+Evaluates to: 0.21
+With type: java.lang.Float
+
+Expression: ${3e-1}
+ExpectedType: double
+Evaluates to: 0.3
+With type: java.lang.Double
+
+Expression: ${.2222222222}
+ExpectedType: double
+Evaluates to: 0.2222222222
+With type: java.lang.Double
+
+
+
+#######################################################
+# basic relationals between literals
+
+Expression: ${1 < 2}
+ExpectedType: boolean
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: ${1 > 2}
+ExpectedType: boolean
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${1 >= 2}
+ExpectedType: boolean
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${1 <= 2}
+ExpectedType: boolean
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: ${1 == 2}
+ExpectedType: boolean
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${1 != 2}
+ExpectedType: boolean
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: ${3 >= 3}
+ExpectedType: boolean
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: ${3 <= 3}
+ExpectedType: boolean
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: ${3 == 3}
+ExpectedType: boolean
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: ${3 < 3}
+ExpectedType: boolean
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${3 > 3}
+ExpectedType: boolean
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${3 != 3}
+ExpectedType: boolean
+Evaluates to: false
+With type: java.lang.Boolean
+
+
+
+#######################################################
+# relationals between booleans
+
+Expression: ${false < true}
+ExpectedType: class java.lang.Object
+Evaluates to: javax.servlet.jsp.JspException: An error occurred while evaluating custom action attribute "test" with value "${false < true}": Attempt to apply operator "<" to arguments of type "java.lang.Boolean" and "java.lang.Boolean"
+With type: javax.servlet.jsp.JspException
+
+Expression: ${false > true}
+ExpectedType: class java.lang.Object
+Evaluates to: javax.servlet.jsp.JspException: An error occurred while evaluating custom action attribute "test" with value "${false > true}": Attempt to apply operator ">" to arguments of type "java.lang.Boolean" and "java.lang.Boolean"
+With type: javax.servlet.jsp.JspException
+
+Expression: ${true >= true}
+ExpectedType: class java.lang.Object
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: ${true <= true}
+ExpectedType: class java.lang.Object
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: ${true == true}
+ExpectedType: class java.lang.Object
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: ${true != true}
+ExpectedType: class java.lang.Object
+Evaluates to: false
+With type: java.lang.Boolean
+
+
+#######################################################
+# looking up objects in scopes
+
+# val1a - defined in page scope
+Expression: ${pageScope.val1a}
+ExpectedType: class java.lang.String
+Evaluates to: page-scoped1
+With type: java.lang.String
+
+Expression: ${requestScope.val1a}
+ExpectedType: class java.lang.String
+Evaluates to: 
+With type: java.lang.String
+
+Expression: ${sessionScope.val1a}
+ExpectedType: class java.lang.String
+Evaluates to: 
+With type: java.lang.String
+
+Expression: ${applicationScope.val1a}
+ExpectedType: class java.lang.String
+Evaluates to: 
+With type: java.lang.String
+
+Expression: ${val1a}
+ExpectedType: class java.lang.String
+Evaluates to: page-scoped1
+With type: java.lang.String
+
+
+# val1b - defined in request scope
+Expression: ${pageScope.val1b}
+ExpectedType: class java.lang.String
+Evaluates to: 
+With type: java.lang.String
+
+Expression: ${requestScope.val1b}
+ExpectedType: class java.lang.String
+Evaluates to: request-scoped1
+With type: java.lang.String
+
+Expression: ${sessionScope.val1b}
+ExpectedType: class java.lang.String
+Evaluates to: 
+With type: java.lang.String
+
+Expression: ${applicationScope.val1b}
+ExpectedType: class java.lang.String
+Evaluates to: 
+With type: java.lang.String
+
+Expression: ${val1b}
+ExpectedType: class java.lang.String
+Evaluates to: request-scoped1
+With type: java.lang.String
+
+
+# val1c - defined in session scope
+Expression: ${pageScope.val1c}
+ExpectedType: class java.lang.String
+Evaluates to: 
+With type: java.lang.String
+
+Expression: ${requestScope.val1c}
+ExpectedType: class java.lang.String
+Evaluates to: 
+With type: java.lang.String
+
+Expression: ${sessionScope.val1c}
+ExpectedType: class java.lang.String
+Evaluates to: session-scoped1
+With type: java.lang.String
+
+Expression: ${applicationScope.val1c}
+ExpectedType: class java.lang.String
+Evaluates to: 
+With type: java.lang.String
+
+Expression: ${val1c}
+ExpectedType: class java.lang.String
+Evaluates to: session-scoped1
+With type: java.lang.String
+
+
+# val1d - defined in application scope
+Expression: ${pageScope.val1d}
+ExpectedType: class java.lang.String
+Evaluates to: 
+With type: java.lang.String
+
+Expression: ${requestScope.val1d}
+ExpectedType: class java.lang.String
+Evaluates to: 
+With type: java.lang.String
+
+Expression: ${sessionScope.val1d}
+ExpectedType: class java.lang.String
+Evaluates to: 
+With type: java.lang.String
+
+Expression: ${applicationScope.val1d}
+ExpectedType: class java.lang.String
+Evaluates to: app-scoped1
+With type: java.lang.String
+
+Expression: ${val1d}
+ExpectedType: class java.lang.String
+Evaluates to: app-scoped1
+With type: java.lang.String
+
+
+#######################################################
+# accessing properties
+
+Expression: ${bean1a.int1}
+ExpectedType: int
+Evaluates to: 4
+With type: java.lang.Integer
+
+Expression: ${bean1a.boolean1}
+ExpectedType: boolean
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: ${bean1a.string1}
+ExpectedType: class java.lang.String
+Evaluates to: hello
+With type: java.lang.String
+
+Expression: ${bean1a.bean1.int2}
+ExpectedType: int
+Evaluates to: -224
+With type: java.lang.Integer
+
+Expression: ${bean1a.bean1.bean2.string2}
+ExpectedType: class java.lang.String
+Evaluates to: bean3's string
+With type: java.lang.String
+
+
+#######################################################
+# test the entire conversion matrix
+
+Expression: ${bean1a.byte1}
+ExpectedType: byte
+Evaluates to: 12
+With type: java.lang.Byte
+
+Expression: ${bean1a.byte1}
+ExpectedType: char
+Evaluates to: 

+With type: java.lang.Character
+
+Expression: ${bean1a.byte1}
+ExpectedType: short
+Evaluates to: 12
+With type: java.lang.Short
+
+Expression: ${bean1a.byte1}
+ExpectedType: int
+Evaluates to: 12
+With type: java.lang.Integer
+
+Expression: ${bean1a.byte1}
+ExpectedType: long
+Evaluates to: 12
+With type: java.lang.Long
+
+Expression: ${bean1a.byte1}
+ExpectedType: float
+Evaluates to: 12.0
+With type: java.lang.Float
+
+Expression: ${bean1a.byte1}
+ExpectedType: double
+Evaluates to: 12.0
+With type: java.lang.Double
+
+
+Expression: ${bean1a.char1}
+ExpectedType: byte
+Evaluates to: 98
+With type: java.lang.Byte
+
+Expression: ${bean1a.char1}
+ExpectedType: char
+Evaluates to: b
+With type: java.lang.Character
+
+Expression: ${bean1a.char1}
+ExpectedType: short
+Evaluates to: 98
+With type: java.lang.Short
+
+Expression: ${bean1a.char1}
+ExpectedType: int
+Evaluates to: 98
+With type: java.lang.Integer
+
+Expression: ${bean1a.char1}
+ExpectedType: long
+Evaluates to: 98
+With type: java.lang.Long
+
+Expression: ${bean1a.char1}
+ExpectedType: float
+Evaluates to: 98.0
+With type: java.lang.Float
+
+Expression: ${bean1a.char1}
+ExpectedType: double
+Evaluates to: 98.0
+With type: java.lang.Double
+
+
+Expression: ${bean1a.short1}
+ExpectedType: byte
+Evaluates to: -124
+With type: java.lang.Byte
+
+Expression: ${bean1a.short1}
+ExpectedType: char
+Evaluates to: ?
+With type: java.lang.Character
+
+Expression: ${bean1a.short1}
+ExpectedType: short
+Evaluates to: -124
+With type: java.lang.Short
+
+Expression: ${bean1a.short1}
+ExpectedType: int
+Evaluates to: -124
+With type: java.lang.Integer
+
+Expression: ${bean1a.short1}
+ExpectedType: long
+Evaluates to: -124
+With type: java.lang.Long
+
+Expression: ${bean1a.short1}
+ExpectedType: float
+Evaluates to: -124.0
+With type: java.lang.Float
+
+Expression: ${bean1a.short1}
+ExpectedType: double
+Evaluates to: -124.0
+With type: java.lang.Double
+
+
+Expression: ${bean1a.int1}
+ExpectedType: byte
+Evaluates to: 4
+With type: java.lang.Byte
+
+Expression: ${bean1a.int1}
+ExpectedType: char
+Evaluates to: 
+With type: java.lang.Character
+
+Expression: ${bean1a.int1}
+ExpectedType: short
+Evaluates to: 4
+With type: java.lang.Short
+
+Expression: ${bean1a.int1}
+ExpectedType: int
+Evaluates to: 4
+With type: java.lang.Integer
+
+Expression: ${bean1a.int1}
+ExpectedType: long
+Evaluates to: 4
+With type: java.lang.Long
+
+Expression: ${bean1a.int1}
+ExpectedType: float
+Evaluates to: 4.0
+With type: java.lang.Float
+
+Expression: ${bean1a.int1}
+ExpectedType: double
+Evaluates to: 4.0
+With type: java.lang.Double
+
+
+Expression: ${bean1a.long1}
+ExpectedType: byte
+Evaluates to: -41
+With type: java.lang.Byte
+
+Expression: ${bean1a.long1}
+ExpectedType: char
+Evaluates to: ?
+With type: java.lang.Character
+
+Expression: ${bean1a.long1}
+ExpectedType: short
+Evaluates to: 25815
+With type: java.lang.Short
+
+Expression: ${bean1a.long1}
+ExpectedType: int
+Evaluates to: 222423
+With type: java.lang.Integer
+
+Expression: ${bean1a.long1}
+ExpectedType: long
+Evaluates to: 222423
+With type: java.lang.Long
+
+Expression: ${bean1a.long1}
+ExpectedType: float
+Evaluates to: 222423.0
+With type: java.lang.Float
+
+Expression: ${bean1a.long1}
+ExpectedType: double
+Evaluates to: 222423.0
+With type: java.lang.Double
+
+
+Expression: ${bean1a.float1}
+ExpectedType: byte
+Evaluates to: 12
+With type: java.lang.Byte
+
+Expression: ${bean1a.float1}
+ExpectedType: char
+Evaluates to: 

+With type: java.lang.Character
+
+Expression: ${bean1a.float1}
+ExpectedType: short
+Evaluates to: 12
+With type: java.lang.Short
+
+Expression: ${bean1a.float1}
+ExpectedType: int
+Evaluates to: 12
+With type: java.lang.Integer
+
+Expression: ${bean1a.float1}
+ExpectedType: long
+Evaluates to: 12
+With type: java.lang.Long
+
+Expression: ${bean1a.float1}
+ExpectedType: float
+Evaluates to: 12.4
+With type: java.lang.Float
+
+Expression: ${bean1a.float1}
+ExpectedType: double
+Evaluates to: 12.399999618530273
+With type: java.lang.Double
+
+
+Expression: ${bean1a.double1}
+ExpectedType: byte
+Evaluates to: 89
+With type: java.lang.Byte
+
+Expression: ${bean1a.double1}
+ExpectedType: char
+Evaluates to: Y
+With type: java.lang.Character
+
+Expression: ${bean1a.double1}
+ExpectedType: short
+Evaluates to: 89
+With type: java.lang.Short
+
+Expression: ${bean1a.double1}
+ExpectedType: int
+Evaluates to: 89
+With type: java.lang.Integer
+
+Expression: ${bean1a.double1}
+ExpectedType: long
+Evaluates to: 89
+With type: java.lang.Long
+
+Expression: ${bean1a.double1}
+ExpectedType: float
+Evaluates to: 89.224
+With type: java.lang.Float
+
+Expression: ${bean1a.double1}
+ExpectedType: double
+Evaluates to: 89.224
+With type: java.lang.Double
+
+
+#######################################################
+# test the entire relational comparison type promotion matrix
+
+Expression: ${bean1a.byte1 < bean1a.byte1}
+ExpectedType: boolean
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${bean1a.byte1 < bean1a.char1}
+ExpectedType: boolean
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: ${bean1a.byte1 < bean1a.short1}
+ExpectedType: boolean
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${bean1a.byte1 < bean1a.int1}
+ExpectedType: boolean
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${bean1a.byte1 < bean1a.long1}
+ExpectedType: boolean
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: ${bean1a.byte1 < bean1a.float1}
+ExpectedType: boolean
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: ${bean1a.byte1 < bean1a.double1}
+ExpectedType: boolean
+Evaluates to: true
+With type: java.lang.Boolean
+
+
+Expression: ${bean1a.char1 < bean1a.byte1}
+ExpectedType: boolean
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${bean1a.char1 < bean1a.char1}
+ExpectedType: boolean
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${bean1a.char1 < bean1a.short1}
+ExpectedType: boolean
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${bean1a.char1 < bean1a.int1}
+ExpectedType: boolean
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${bean1a.char1 < bean1a.long1}
+ExpectedType: boolean
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: ${bean1a.char1 < bean1a.float1}
+ExpectedType: boolean
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${bean1a.char1 < bean1a.double1}
+ExpectedType: boolean
+Evaluates to: false
+With type: java.lang.Boolean
+
+
+Expression: ${bean1a.short1 < bean1a.byte1}
+ExpectedType: boolean
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: ${bean1a.short1 < bean1a.char1}
+ExpectedType: boolean
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: ${bean1a.short1 < bean1a.short1}
+ExpectedType: boolean
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${bean1a.short1 < bean1a.int1}
+ExpectedType: boolean
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: ${bean1a.short1 < bean1a.long1}
+ExpectedType: boolean
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: ${bean1a.short1 < bean1a.float1}
+ExpectedType: boolean
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: ${bean1a.short1 < bean1a.double1}
+ExpectedType: boolean
+Evaluates to: true
+With type: java.lang.Boolean
+
+
+Expression: ${bean1a.int1 < bean1a.byte1}
+ExpectedType: boolean
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: ${bean1a.int1 < bean1a.char1}
+ExpectedType: boolean
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: ${bean1a.int1 < bean1a.short1}
+ExpectedType: boolean
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${bean1a.int1 < bean1a.int1}
+ExpectedType: boolean
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${bean1a.int1 < bean1a.long1}
+ExpectedType: boolean
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: ${bean1a.int1 < bean1a.float1}
+ExpectedType: boolean
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: ${bean1a.int1 < bean1a.double1}
+ExpectedType: boolean
+Evaluates to: true
+With type: java.lang.Boolean
+
+
+Expression: ${bean1a.long1 < bean1a.byte1}
+ExpectedType: boolean
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${bean1a.long1 < bean1a.char1}
+ExpectedType: boolean
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${bean1a.long1 < bean1a.short1}
+ExpectedType: boolean
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${bean1a.long1 < bean1a.int1}
+ExpectedType: boolean
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${bean1a.long1 < bean1a.long1}
+ExpectedType: boolean
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${bean1a.long1 < bean1a.float1}
+ExpectedType: boolean
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${bean1a.long1 < bean1a.double1}
+ExpectedType: boolean
+Evaluates to: false
+With type: java.lang.Boolean
+
+
+Expression: ${bean1a.float1 < bean1a.byte1}
+ExpectedType: boolean
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${bean1a.float1 < bean1a.char1}
+ExpectedType: boolean
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: ${bean1a.float1 < bean1a.short1}
+ExpectedType: boolean
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${bean1a.float1 < bean1a.int1}
+ExpectedType: boolean
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${bean1a.float1 < bean1a.long1}
+ExpectedType: boolean
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: ${bean1a.float1 < bean1a.float1}
+ExpectedType: boolean
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${bean1a.float1 < bean1a.double1}
+ExpectedType: boolean
+Evaluates to: true
+With type: java.lang.Boolean
+
+
+Expression: ${bean1a.double1 < bean1a.byte1}
+ExpectedType: boolean
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${bean1a.double1 < bean1a.char1}
+ExpectedType: boolean
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: ${bean1a.double1 < bean1a.short1}
+ExpectedType: boolean
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${bean1a.double1 < bean1a.int1}
+ExpectedType: boolean
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${bean1a.double1 < bean1a.long1}
+ExpectedType: boolean
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: ${bean1a.double1 < bean1a.float1}
+ExpectedType: boolean
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${bean1a.double1 < bean1a.double1}
+ExpectedType: boolean
+Evaluates to: false
+With type: java.lang.Boolean
+
+
+#######################################################
+# test other relational comparison rules
+
+Expression: ${null == null}
+ExpectedType: boolean
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: ${noSuchAttribute == noSuchAttribute}
+ExpectedType: boolean
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: ${noSuchAttribute == null}
+ExpectedType: boolean
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: ${null == noSuchAttribute}
+ExpectedType: boolean
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: ${bean1a == null}
+ExpectedType: boolean
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${null == bean1a}
+ExpectedType: boolean
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${bean1a == bean1a}
+ExpectedType: boolean
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: ${bean1a > "hello"}
+ExpectedType: boolean
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: ${bean1a.bean1 < 14}
+ExpectedType: boolean
+Evaluates to: javax.servlet.jsp.JspException: An error occurred while evaluating custom action attribute "test" with value "${bean1a.bean1 < 14}": Attempt to coerce a value of type "org.apache.taglibs.standard.lang.jstl.test.Bean1" to type "java.lang.Long"
+With type: javax.servlet.jsp.JspException
+
+Expression: ${bean1a.bean1 == "hello"}
+ExpectedType: boolean
+Evaluates to: false
+With type: java.lang.Boolean
+
+
+#######################################################
+# test String comparisons
+
+Expression: ${bean1a.string1 == "hello"}
+ExpectedType: boolean
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: ${bean1a.string1 != "hello"}
+ExpectedType: boolean
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${bean1a.string1 == "goodbye"}
+ExpectedType: boolean
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${bean1a.string1 != "goodbye"}
+ExpectedType: boolean
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: ${bean1a.string1 > "goodbye"}
+ExpectedType: boolean
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: ${"hello" == bean1a.string1}
+ExpectedType: boolean
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: ${"goodbye" > bean1a.string1}
+ExpectedType: boolean
+Evaluates to: false
+With type: java.lang.Boolean
+
+
+#######################################################
+# test errors in property traversal
+
+Expression: ${noSuchAttribute.abc}
+ExpectedType: class java.lang.Object
+Evaluates to: null
+
+Expression: ${bean1a.bean2.byte1}
+ExpectedType: class java.lang.Object
+Evaluates to: null
+
+Expression: ${bean1a.noProperty}
+ExpectedType: class java.lang.Object
+Evaluates to: javax.servlet.jsp.JspException: An error occurred while evaluating custom action attribute "test" with value "${bean1a.noProperty}": Unable to find a value for "noProperty" in object of class "org.apache.taglibs.standard.lang.jstl.test.Bean1" using operator "."
+With type: javax.servlet.jsp.JspException
+
+Expression: ${bean1a.noGetter}
+ExpectedType: class java.lang.Object
+Evaluates to: javax.servlet.jsp.JspException: An error occurred while evaluating custom action attribute "test" with value "${bean1a.noGetter}": Unable to find a value for "noGetter" in object of class "org.apache.taglibs.standard.lang.jstl.test.Bean1" using operator "."
+With type: javax.servlet.jsp.JspException
+
+Expression: ${bean1a.errorInGetter}
+ExpectedType: class java.lang.Object
+Evaluates to: javax.servlet.jsp.JspException: An error occurred while evaluating custom action attribute "test" with value "${bean1a.errorInGetter}": An error occurred while getting property "errorInGetter" from an instance of class org.apache.taglibs.standard.lang.jstl.test.Bean1
+With type: javax.servlet.jsp.JspException
+
+Expression: ${bean1a.bean2.string2}
+ExpectedType: class java.lang.Object
+Evaluates to: null
+
+
+#######################################################
+# test accessing public properties from private classes
+
+Expression: ${pbean1.value}
+ExpectedType: class java.lang.Object
+Evaluates to: got the value
+With type: java.lang.String
+
+Expression: ${pbean2.value}
+ExpectedType: class java.lang.Object
+Evaluates to: got the value
+With type: java.lang.String
+
+Expression: ${pbean3.value}
+ExpectedType: class java.lang.Object
+Evaluates to: got the value
+With type: java.lang.String
+
+Expression: ${pbean4.value}
+ExpectedType: class java.lang.Object
+Evaluates to: got the value
+With type: java.lang.String
+
+Expression: ${pbean5.value}
+ExpectedType: class java.lang.Object
+Evaluates to: got the value
+With type: java.lang.String
+
+Expression: ${pbean6.value}
+ExpectedType: class java.lang.Object
+Evaluates to: got the value
+With type: java.lang.String
+
+Expression: ${pbean7.value}
+ExpectedType: class java.lang.Object
+Evaluates to: got the value
+With type: java.lang.String
+
+
+#######################################################
+# test literal conversions
+
+Expression: true
+ExpectedType: boolean
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: false
+ExpectedType: boolean
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: 12
+ExpectedType: byte
+Evaluates to: 12
+With type: java.lang.Byte
+
+Expression: 12
+ExpectedType: char
+Evaluates to: 1
+With type: java.lang.Character
+
+Expression: 12
+ExpectedType: short
+Evaluates to: 12
+With type: java.lang.Short
+
+Expression: 12
+ExpectedType: int
+Evaluates to: 12
+With type: java.lang.Integer
+
+Expression: 12
+ExpectedType: long
+Evaluates to: 12
+With type: java.lang.Long
+
+Expression: 12
+ExpectedType: float
+Evaluates to: 12.0
+With type: java.lang.Float
+
+Expression: 12
+ExpectedType: double
+Evaluates to: 12.0
+With type: java.lang.Double
+
+
+Expression: hello
+ExpectedType: class org.apache.taglibs.standard.lang.jstl.test.Bean2
+Evaluates to: Bean2[hello]
+With type: org.apache.taglibs.standard.lang.jstl.test.Bean2
+
+Expression: badvalue
+ExpectedType: class org.apache.taglibs.standard.lang.jstl.test.Bean2
+Evaluates to: javax.servlet.jsp.JspException: An error occurred while evaluating custom action attribute "test" with value "badvalue": Unable to parse value "badvalue" into expected type "org.apache.taglibs.standard.lang.jstl.test.Bean2"
+With type: javax.servlet.jsp.JspException
+
+Expression: hello
+ExpectedType: class org.apache.taglibs.standard.lang.jstl.test.Bean1
+Evaluates to: javax.servlet.jsp.JspException: An error occurred while evaluating custom action attribute "test" with value "hello": Attempt to convert String "hello" to type "org.apache.taglibs.standard.lang.jstl.test.Bean1", but there is no PropertyEditor for that type
+With type: javax.servlet.jsp.JspException
+
+
+#######################################################
+# test null values bumped up to constants
+
+Expression: ${null}
+ExpectedType: boolean
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${null}
+ExpectedType: byte
+Evaluates to: 0
+With type: java.lang.Byte
+
+Expression: ${null}
+ExpectedType: short
+Evaluates to: 0
+With type: java.lang.Short
+
+Expression: ${null}
+ExpectedType: char
+Evaluates to: 
+With type: java.lang.Character
+
+Expression: ${null}
+ExpectedType: int
+Evaluates to: 0
+With type: java.lang.Integer
+
+Expression: ${null}
+ExpectedType: long
+Evaluates to: 0
+With type: java.lang.Long
+
+Expression: ${null}
+ExpectedType: float
+Evaluates to: 0.0
+With type: java.lang.Float
+
+Expression: ${null}
+ExpectedType: double
+Evaluates to: 0.0
+With type: java.lang.Double
+
+Expression: ${null}
+ExpectedType: class java.lang.Boolean
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${null}
+ExpectedType: class java.lang.Byte
+Evaluates to: 0
+With type: java.lang.Byte
+
+Expression: ${null}
+ExpectedType: class java.lang.Short
+Evaluates to: 0
+With type: java.lang.Short
+
+Expression: ${null}
+ExpectedType: class java.lang.Character
+Evaluates to: 
+With type: java.lang.Character
+
+Expression: ${null}
+ExpectedType: class java.lang.Integer
+Evaluates to: 0
+With type: java.lang.Integer
+
+Expression: ${null}
+ExpectedType: class java.lang.Long
+Evaluates to: 0
+With type: java.lang.Long
+
+Expression: ${null}
+ExpectedType: class java.lang.Float
+Evaluates to: 0.0
+With type: java.lang.Float
+
+Expression: ${null}
+ExpectedType: class java.lang.Double
+Evaluates to: 0.0
+With type: java.lang.Double
+
+
+
+#######################################################
+# test reserved words as identifiers
+
+Expression: ${and}
+ExpectedType: class java.lang.Object
+Evaluates to: javax.servlet.jsp.JspException: An error occurred while evaluating custom action attribute "test" with value "${and}": Encountered "and", expected one of [<INTEGER_LITERAL>, <FLOATING_POINT_LITERAL>, <STRING_LITERAL>, "true", "false", "null", "(", "-", "not", "!", "empty", <IDENTIFIER>]
+With type: javax.servlet.jsp.JspException
+
+Expression: ${or}
+ExpectedType: class java.lang.Object
+Evaluates to: javax.servlet.jsp.JspException: An error occurred while evaluating custom action attribute "test" with value "${or}": Encountered "or", expected one of [<INTEGER_LITERAL>, <FLOATING_POINT_LITERAL>, <STRING_LITERAL>, "true", "false", "null", "(", "-", "not", "!", "empty", <IDENTIFIER>]
+With type: javax.servlet.jsp.JspException
+
+Expression: ${not}
+ExpectedType: class java.lang.Object
+Evaluates to: javax.servlet.jsp.JspException: An error occurred while evaluating custom action attribute "test" with value "${not}": Encountered "}", expected one of [<INTEGER_LITERAL>, <FLOATING_POINT_LITERAL>, <STRING_LITERAL>, "true", "false", "null", "(", "-", "not", "!", "empty", <IDENTIFIER>]
+With type: javax.servlet.jsp.JspException
+
+Expression: ${eq}
+ExpectedType: class java.lang.Object
+Evaluates to: javax.servlet.jsp.JspException: An error occurred while evaluating custom action attribute "test" with value "${eq}": Encountered "eq", expected one of [<INTEGER_LITERAL>, <FLOATING_POINT_LITERAL>, <STRING_LITERAL>, "true", "false", "null", "(", "-", "not", "!", "empty", <IDENTIFIER>]
+With type: javax.servlet.jsp.JspException
+
+Expression: ${ne}
+ExpectedType: class java.lang.Object
+Evaluates to: javax.servlet.jsp.JspException: An error occurred while evaluating custom action attribute "test" with value "${ne}": Encountered "ne", expected one of [<INTEGER_LITERAL>, <FLOATING_POINT_LITERAL>, <STRING_LITERAL>, "true", "false", "null", "(", "-", "not", "!", "empty", <IDENTIFIER>]
+With type: javax.servlet.jsp.JspException
+
+Expression: ${lt}
+ExpectedType: class java.lang.Object
+Evaluates to: javax.servlet.jsp.JspException: An error occurred while evaluating custom action attribute "test" with value "${lt}": Encountered "lt", expected one of [<INTEGER_LITERAL>, <FLOATING_POINT_LITERAL>, <STRING_LITERAL>, "true", "false", "null", "(", "-", "not", "!", "empty", <IDENTIFIER>]
+With type: javax.servlet.jsp.JspException
+
+Expression: ${gt}
+ExpectedType: class java.lang.Object
+Evaluates to: javax.servlet.jsp.JspException: An error occurred while evaluating custom action attribute "test" with value "${gt}": Encountered "gt", expected one of [<INTEGER_LITERAL>, <FLOATING_POINT_LITERAL>, <STRING_LITERAL>, "true", "false", "null", "(", "-", "not", "!", "empty", <IDENTIFIER>]
+With type: javax.servlet.jsp.JspException
+
+Expression: ${le}
+ExpectedType: class java.lang.Object
+Evaluates to: javax.servlet.jsp.JspException: An error occurred while evaluating custom action attribute "test" with value "${le}": Encountered "le", expected one of [<INTEGER_LITERAL>, <FLOATING_POINT_LITERAL>, <STRING_LITERAL>, "true", "false", "null", "(", "-", "not", "!", "empty", <IDENTIFIER>]
+With type: javax.servlet.jsp.JspException
+
+Expression: ${ge}
+ExpectedType: class java.lang.Object
+Evaluates to: javax.servlet.jsp.JspException: An error occurred while evaluating custom action attribute "test" with value "${ge}": Encountered "ge", expected one of [<INTEGER_LITERAL>, <FLOATING_POINT_LITERAL>, <STRING_LITERAL>, "true", "false", "null", "(", "-", "not", "!", "empty", <IDENTIFIER>]
+With type: javax.servlet.jsp.JspException
+
+Expression: ${instanceof}
+ExpectedType: class java.lang.Object
+Evaluates to: null
+
+Expression: ${true}
+ExpectedType: class java.lang.Object
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: ${false}
+ExpectedType: class java.lang.Object
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${null}
+ExpectedType: class java.lang.Object
+Evaluates to: null
+
+
+
+#######################################################
+# test reserved words as property names
+
+Expression: ${bean1a.and}
+ExpectedType: class java.lang.Object
+Evaluates to: javax.servlet.jsp.JspException: An error occurred while evaluating custom action attribute "test" with value "${bean1a.and}": Encountered "and", expected one of [<IDENTIFIER>]
+With type: javax.servlet.jsp.JspException
+
+Expression: ${bean1a.or}
+ExpectedType: class java.lang.Object
+Evaluates to: javax.servlet.jsp.JspException: An error occurred while evaluating custom action attribute "test" with value "${bean1a.or}": Encountered "or", expected one of [<IDENTIFIER>]
+With type: javax.servlet.jsp.JspException
+
+Expression: ${bean1a.not}
+ExpectedType: class java.lang.Object
+Evaluates to: javax.servlet.jsp.JspException: An error occurred while evaluating custom action attribute "test" with value "${bean1a.not}": Encountered "not", expected one of [<IDENTIFIER>]
+With type: javax.servlet.jsp.JspException
+
+Expression: ${bean1a.eq}
+ExpectedType: class java.lang.Object
+Evaluates to: javax.servlet.jsp.JspException: An error occurred while evaluating custom action attribute "test" with value "${bean1a.eq}": Encountered "eq", expected one of [<IDENTIFIER>]
+With type: javax.servlet.jsp.JspException
+
+Expression: ${bean1a.ne}
+ExpectedType: class java.lang.Object
+Evaluates to: javax.servlet.jsp.JspException: An error occurred while evaluating custom action attribute "test" with value "${bean1a.ne}": Encountered "ne", expected one of [<IDENTIFIER>]
+With type: javax.servlet.jsp.JspException
+
+Expression: ${bean1a.lt}
+ExpectedType: class java.lang.Object
+Evaluates to: javax.servlet.jsp.JspException: An error occurred while evaluating custom action attribute "test" with value "${bean1a.lt}": Encountered "lt", expected one of [<IDENTIFIER>]
+With type: javax.servlet.jsp.JspException
+
+Expression: ${bean1a.gt}
+ExpectedType: class java.lang.Object
+Evaluates to: javax.servlet.jsp.JspException: An error occurred while evaluating custom action attribute "test" with value "${bean1a.gt}": Encountered "gt", expected one of [<IDENTIFIER>]
+With type: javax.servlet.jsp.JspException
+
+Expression: ${bean1a.le}
+ExpectedType: class java.lang.Object
+Evaluates to: javax.servlet.jsp.JspException: An error occurred while evaluating custom action attribute "test" with value "${bean1a.le}": Encountered "le", expected one of [<IDENTIFIER>]
+With type: javax.servlet.jsp.JspException
+
+Expression: ${bean1a.ge}
+ExpectedType: class java.lang.Object
+Evaluates to: javax.servlet.jsp.JspException: An error occurred while evaluating custom action attribute "test" with value "${bean1a.ge}": Encountered "ge", expected one of [<IDENTIFIER>]
+With type: javax.servlet.jsp.JspException
+
+Expression: ${bean1a.instanceof}
+ExpectedType: class java.lang.Object
+Evaluates to: javax.servlet.jsp.JspException: An error occurred while evaluating custom action attribute "test" with value "${bean1a.instanceof}": Unable to find a value for "instanceof" in object of class "org.apache.taglibs.standard.lang.jstl.test.Bean1" using operator "."
+With type: javax.servlet.jsp.JspException
+
+Expression: ${bean1a.page}
+ExpectedType: class java.lang.Object
+Evaluates to: javax.servlet.jsp.JspException: An error occurred while evaluating custom action attribute "test" with value "${bean1a.page}": Unable to find a value for "page" in object of class "org.apache.taglibs.standard.lang.jstl.test.Bean1" using operator "."
+With type: javax.servlet.jsp.JspException
+
+Expression: ${bean1a.request}
+ExpectedType: class java.lang.Object
+Evaluates to: javax.servlet.jsp.JspException: An error occurred while evaluating custom action attribute "test" with value "${bean1a.request}": Unable to find a value for "request" in object of class "org.apache.taglibs.standard.lang.jstl.test.Bean1" using operator "."
+With type: javax.servlet.jsp.JspException
+
+Expression: ${bean1a.session}
+ExpectedType: class java.lang.Object
+Evaluates to: javax.servlet.jsp.JspException: An error occurred while evaluating custom action attribute "test" with value "${bean1a.session}": Unable to find a value for "session" in object of class "org.apache.taglibs.standard.lang.jstl.test.Bean1" using operator "."
+With type: javax.servlet.jsp.JspException
+
+Expression: ${bean1a.application}
+ExpectedType: class java.lang.Object
+Evaluates to: javax.servlet.jsp.JspException: An error occurred while evaluating custom action attribute "test" with value "${bean1a.application}": Unable to find a value for "application" in object of class "org.apache.taglibs.standard.lang.jstl.test.Bean1" using operator "."
+With type: javax.servlet.jsp.JspException
+
+Expression: ${bean1a.true}
+ExpectedType: class java.lang.Object
+Evaluates to: javax.servlet.jsp.JspException: An error occurred while evaluating custom action attribute "test" with value "${bean1a.true}": Encountered "true", expected one of [<IDENTIFIER>]
+With type: javax.servlet.jsp.JspException
+
+Expression: ${bean1a.false}
+ExpectedType: class java.lang.Object
+Evaluates to: javax.servlet.jsp.JspException: An error occurred while evaluating custom action attribute "test" with value "${bean1a.false}": Encountered "false", expected one of [<IDENTIFIER>]
+With type: javax.servlet.jsp.JspException
+
+Expression: ${bean1a.null}
+ExpectedType: class java.lang.Object
+Evaluates to: javax.servlet.jsp.JspException: An error occurred while evaluating custom action attribute "test" with value "${bean1a.null}": Encountered "null", expected one of [<IDENTIFIER>]
+With type: javax.servlet.jsp.JspException
+
+
+#######################################################
+# test arithmetic
+
+Expression: ${3+5}
+ExpectedType: class java.lang.Object
+Evaluates to: 8
+With type: java.lang.Long
+
+Expression: ${3-5}
+ExpectedType: class java.lang.Object
+Evaluates to: -2
+With type: java.lang.Long
+
+Expression: ${3/5}
+ExpectedType: class java.lang.Object
+Evaluates to: 0.6
+With type: java.lang.Double
+
+Expression: ${3*5}
+ExpectedType: class java.lang.Object
+Evaluates to: 15
+With type: java.lang.Long
+
+Expression: ${3*5.0}
+ExpectedType: class java.lang.Object
+Evaluates to: 15.0
+With type: java.lang.Double
+
+Expression: ${3.0*5}
+ExpectedType: class java.lang.Object
+Evaluates to: 15.0
+With type: java.lang.Double
+
+Expression: ${3.0*5.0}
+ExpectedType: class java.lang.Object
+Evaluates to: 15.0
+With type: java.lang.Double
+
+Expression: ${225 % 17}
+ExpectedType: class java.lang.Object
+Evaluates to: 4
+With type: java.lang.Long
+
+
+Expression: ${ 1 + 2 + 3 * 5 + 6}
+ExpectedType: class java.lang.Object
+Evaluates to: 24
+With type: java.lang.Long
+
+Expression: ${ 1 + (2 + 3) * 5 + 6}
+ExpectedType: class java.lang.Object
+Evaluates to: 32
+With type: java.lang.Long
+
+
+#######################################################
+# test logical operators
+
+Expression: ${ true}
+ExpectedType: class java.lang.Object
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: ${ not true}
+ExpectedType: class java.lang.Object
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${ not false}
+ExpectedType: class java.lang.Object
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: ${ not not true}
+ExpectedType: class java.lang.Object
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: ${ not not false}
+ExpectedType: class java.lang.Object
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${ true and false}
+ExpectedType: class java.lang.Object
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${ true and true}
+ExpectedType: class java.lang.Object
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: ${ false and true}
+ExpectedType: class java.lang.Object
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${ false and false}
+ExpectedType: class java.lang.Object
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${ true or false}
+ExpectedType: class java.lang.Object
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: ${ true or true}
+ExpectedType: class java.lang.Object
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: ${ false or true}
+ExpectedType: class java.lang.Object
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: ${ false or false}
+ExpectedType: class java.lang.Object
+Evaluates to: false
+With type: java.lang.Boolean
+
+
+Expression: ${ false or false or false or true and false}
+ExpectedType: class java.lang.Object
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${ false or false or false or true and false or true}
+ExpectedType: class java.lang.Object
+Evaluates to: true
+With type: java.lang.Boolean
+
+
+#######################################################
+# test indexed access operator
+
+# Test as equivalent to property accessor
+Expression: ${ bean1a["double1"] }
+ExpectedType: class java.lang.Object
+Evaluates to: 89.224
+With type: java.lang.Double
+
+Expression: ${ bean1a["double1"].class }
+ExpectedType: class java.lang.Object
+Evaluates to: class java.lang.Double
+With type: java.lang.Class
+
+
+# Test as array accessor
+Expression: ${ bean1a.stringArray1[-1]}
+ExpectedType: class java.lang.Object
+Evaluates to: null
+
+Expression: ${ bean1a.stringArray1[0]}
+ExpectedType: class java.lang.Object
+Evaluates to: string1
+With type: java.lang.String
+
+Expression: ${ bean1a.stringArray1[1]}
+ExpectedType: class java.lang.Object
+Evaluates to: string2
+With type: java.lang.String
+
+Expression: ${ bean1a.stringArray1[2]}
+ExpectedType: class java.lang.Object
+Evaluates to: string3
+With type: java.lang.String
+
+Expression: ${ bean1a.stringArray1[3]}
+ExpectedType: class java.lang.Object
+Evaluates to: string4
+With type: java.lang.String
+
+Expression: ${ bean1a.stringArray1[4]}
+ExpectedType: class java.lang.Object
+Evaluates to: null
+
+
+# Test as list accessor
+Expression: ${ bean1a.list1 [0] }
+ExpectedType: class java.lang.Object
+Evaluates to: 14
+With type: java.lang.Integer
+
+Expression: ${ bean1a.list1 [1] }
+ExpectedType: class java.lang.Object
+Evaluates to: another value
+With type: java.lang.String
+
+Expression: ${ bean1a.list1 [2][2] }
+ExpectedType: class java.lang.Object
+Evaluates to: string3
+With type: java.lang.String
+
+
+# Test as indexed property accessor
+Expression: ${ bean1a.indexed1[-1]}
+ExpectedType: class java.lang.Object
+Evaluates to: javax.servlet.jsp.JspException: An error occurred while evaluating custom action attribute "test" with value "${ bean1a.indexed1[-1]}": Unable to find a value for "indexed1" in object of class "org.apache.taglibs.standard.lang.jstl.test.Bean1" using operator "."
+With type: javax.servlet.jsp.JspException
+
+Expression: ${ bean1a.indexed1[0]}
+ExpectedType: class java.lang.Object
+Evaluates to: javax.servlet.jsp.JspException: An error occurred while evaluating custom action attribute "test" with value "${ bean1a.indexed1[0]}": Unable to find a value for "indexed1" in object of class "org.apache.taglibs.standard.lang.jstl.test.Bean1" using operator "."
+With type: javax.servlet.jsp.JspException
+
+Expression: ${ bean1a.indexed1[1]}
+ExpectedType: class java.lang.Object
+Evaluates to: javax.servlet.jsp.JspException: An error occurred while evaluating custom action attribute "test" with value "${ bean1a.indexed1[1]}": Unable to find a value for "indexed1" in object of class "org.apache.taglibs.standard.lang.jstl.test.Bean1" using operator "."
+With type: javax.servlet.jsp.JspException
+
+Expression: ${ bean1a.indexed1[2]}
+ExpectedType: class java.lang.Object
+Evaluates to: javax.servlet.jsp.JspException: An error occurred while evaluating custom action attribute "test" with value "${ bean1a.indexed1[2]}": Unable to find a value for "indexed1" in object of class "org.apache.taglibs.standard.lang.jstl.test.Bean1" using operator "."
+With type: javax.servlet.jsp.JspException
+
+Expression: ${ bean1a.indexed1[3]}
+ExpectedType: class java.lang.Object
+Evaluates to: javax.servlet.jsp.JspException: An error occurred while evaluating custom action attribute "test" with value "${ bean1a.indexed1[3]}": Unable to find a value for "indexed1" in object of class "org.apache.taglibs.standard.lang.jstl.test.Bean1" using operator "."
+With type: javax.servlet.jsp.JspException
+
+Expression: ${ bean1a.indexed1[4]}
+ExpectedType: class java.lang.Object
+Evaluates to: javax.servlet.jsp.JspException: An error occurred while evaluating custom action attribute "test" with value "${ bean1a.indexed1[4]}": Unable to find a value for "indexed1" in object of class "org.apache.taglibs.standard.lang.jstl.test.Bean1" using operator "."
+With type: javax.servlet.jsp.JspException
+
+
+# Test as map accessor
+Expression: ${ bean1a.map1.key1 }
+ExpectedType: class java.lang.Object
+Evaluates to: value1
+With type: java.lang.String
+
+Expression: ${ bean1a.map1 ["key1"] }
+ExpectedType: class java.lang.Object
+Evaluates to: value1
+With type: java.lang.String
+
+Expression: ${ bean1a.map1 [14] }
+ExpectedType: class java.lang.Object
+Evaluates to: value3
+With type: java.lang.String
+
+Expression: ${ bean1a.map1 [2 * 7] }
+ExpectedType: class java.lang.Object
+Evaluates to: value3
+With type: java.lang.String
+
+Expression: ${ bean1a.map1.recurse.list1[0] }
+ExpectedType: class java.lang.Object
+Evaluates to: 14
+With type: java.lang.Integer
+
+
+#######################################################
+# test String concatenation
+
+Expression: ${ "a" + "bcd" }
+ExpectedType: class java.lang.Object
+Evaluates to: javax.servlet.jsp.JspException: An error occurred while evaluating custom action attribute "test" with value "${ "a" + "bcd" }": An exception occured trying to convert String "a" to type "java.lang.Long"
+With type: javax.servlet.jsp.JspException
+
+Expression: ${ "a" + (4*3) }
+ExpectedType: class java.lang.Object
+Evaluates to: javax.servlet.jsp.JspException: An error occurred while evaluating custom action attribute "test" with value "${ "a" + (4*3) }": An exception occured trying to convert String "a" to type "java.lang.Long"
+With type: javax.servlet.jsp.JspException
+
+Expression: ${ bean1a.map1 ["key" + (5-4)] }
+ExpectedType: class java.lang.Object
+Evaluates to: javax.servlet.jsp.JspException: An error occurred while evaluating custom action attribute "test" with value "${ bean1a.map1 ["key" + (5-4)] }": An exception occured trying to convert String "key" to type "java.lang.Double"
+With type: javax.servlet.jsp.JspException
+
+
+#######################################################
+# test String comparisons
+
+Expression: ${ "30" < "4" }
+ExpectedType: class java.lang.Object
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: ${ 30 < "4" }
+ExpectedType: class java.lang.Object
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${ 30 > "4" }
+ExpectedType: class java.lang.Object
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: ${ "0004" == "4" }
+ExpectedType: class java.lang.Object
+Evaluates to: false
+With type: java.lang.Boolean
+
+
+#######################################################
+# test relational comparison with alternate symbols
+
+Expression: ${ 4 eq 3}
+ExpectedType: class java.lang.Object
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${ 4 ne 3}
+ExpectedType: class java.lang.Object
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: ${ 4 eq 4}
+ExpectedType: class java.lang.Object
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: ${ 4 ne 4}
+ExpectedType: class java.lang.Object
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${ 4 lt 3}
+ExpectedType: class java.lang.Object
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${ 4 gt 3}
+ExpectedType: class java.lang.Object
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: ${ 4 le 3}
+ExpectedType: class java.lang.Object
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${ 4 ge 3}
+ExpectedType: class java.lang.Object
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: ${ 4 le 4}
+ExpectedType: class java.lang.Object
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: ${ 4 ge 4}
+ExpectedType: class java.lang.Object
+Evaluates to: true
+With type: java.lang.Boolean
+
+
+#######################################################
+# test expressions on the left side of a value suffix
+
+Expression: ${(3).class}
+ExpectedType: class java.lang.Object
+Evaluates to: class java.lang.Long
+With type: java.lang.Class
+
+Expression: ${(bean1a.map1)["key1"]}
+ExpectedType: class java.lang.Object
+Evaluates to: value1
+With type: java.lang.String
+
+
+
+#######################################################
+# test String/boolean logical operators
+
+Expression: ${'true' and false}
+ExpectedType: class java.lang.Object
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${'true' or true}
+ExpectedType: class java.lang.Object
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: ${false and 'true'}
+ExpectedType: class java.lang.Object
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${false or 'true'}
+ExpectedType: class java.lang.Object
+Evaluates to: true
+With type: java.lang.Boolean
+
+
+#######################################################
+# test empty operator
+
+Expression: ${ empty "A"}
+ExpectedType: class java.lang.Object
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${ empty "" }
+ExpectedType: class java.lang.Object
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: ${ empty null }
+ExpectedType: class java.lang.Object
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: ${ empty false}
+ExpectedType: class java.lang.Object
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${ empty 0}
+ExpectedType: class java.lang.Object
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${ not empty 0}
+ExpectedType: class java.lang.Object
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: ${ not empty empty 0}
+ExpectedType: class java.lang.Object
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: ${ empty emptyTests.emptyArray }
+ExpectedType: class java.lang.Object
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: ${ empty emptyTests.nonemptyArray }
+ExpectedType: class java.lang.Object
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${ empty emptyTests.emptyList }
+ExpectedType: class java.lang.Object
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: ${ empty emptyTests.nonemptyList }
+ExpectedType: class java.lang.Object
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${ empty emptyTests.emptyMap }
+ExpectedType: class java.lang.Object
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: ${ empty emptyTests.nonemptyMap }
+ExpectedType: class java.lang.Object
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${ empty emptyTests.emptySet }
+ExpectedType: class java.lang.Object
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${ empty emptyTests.nonemptySet }
+ExpectedType: class java.lang.Object
+Evaluates to: false
+With type: java.lang.Boolean
+
+
+#######################################################
+# test String arithmetic
+
+Expression: ${ "6" / "3" }
+ExpectedType: class java.lang.Object
+Evaluates to: 2.0
+With type: java.lang.Double
+
+Expression: ${ 3 + "4" }
+ExpectedType: class java.lang.Object
+Evaluates to: 7
+With type: java.lang.Long
+
+Expression: ${ "4" + 3 }
+ExpectedType: class java.lang.Object
+Evaluates to: 7
+With type: java.lang.Long
+
+Expression: ${ 3 + "4.5" }
+ExpectedType: class java.lang.Object
+Evaluates to: 7.5
+With type: java.lang.Double
+
+Expression: ${ "4.5" + 3 }
+ExpectedType: class java.lang.Object
+Evaluates to: 7.5
+With type: java.lang.Double
+
+Expression: ${ 3.0 + 6.0}
+ExpectedType: class java.lang.Object
+Evaluates to: 9.0
+With type: java.lang.Double
+
+Expression: ${ 31121.0 * 61553.0 }
+ExpectedType: class java.lang.Object
+Evaluates to: 1.915590913E9
+With type: java.lang.Double
+
+Expression: ${ 31121 * 61553 }
+ExpectedType: class java.lang.Object
+Evaluates to: 1915590913
+With type: java.lang.Long
+
+Expression: ${ 65536 * 65536 * 65536 * 32759 }
+ExpectedType: class java.lang.Object
+Evaluates to: 9220838762064379904
+With type: java.lang.Long
+
+Expression: ${ 9220838762064379904.0 - 9220838762064379900.0 }
+ExpectedType: class java.lang.Object
+Evaluates to: 0.0
+With type: java.lang.Double
+
+Expression: ${ 9220838762064379904 - 9220838762064379900 }
+ExpectedType: class java.lang.Object
+Evaluates to: 4
+With type: java.lang.Long
+
+
+#######################################################
+# test relational operators involving null
+
+Expression: ${ null == null }
+ExpectedType: class java.lang.Object
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: ${ null != null }
+ExpectedType: class java.lang.Object
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${ null > null }
+ExpectedType: class java.lang.Object
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${ null < null }
+ExpectedType: class java.lang.Object
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${ null >= null }
+ExpectedType: class java.lang.Object
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: ${ null <= null }
+ExpectedType: class java.lang.Object
+Evaluates to: true
+With type: java.lang.Boolean
+
+
+Expression: ${ null == 3 }
+ExpectedType: class java.lang.Object
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${ null != 3 }
+ExpectedType: class java.lang.Object
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: ${ null > 3 }
+ExpectedType: class java.lang.Object
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${ null < 3 }
+ExpectedType: class java.lang.Object
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${ null >= 3 }
+ExpectedType: class java.lang.Object
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${ null <= 3 }
+ExpectedType: class java.lang.Object
+Evaluates to: false
+With type: java.lang.Boolean
+
+
+Expression: ${ 3 == null }
+ExpectedType: class java.lang.Object
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${ 3 != null }
+ExpectedType: class java.lang.Object
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: ${ 3 > null }
+ExpectedType: class java.lang.Object
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${ 3 < null }
+ExpectedType: class java.lang.Object
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${ 3 >= null }
+ExpectedType: class java.lang.Object
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${ 3 <= null }
+ExpectedType: class java.lang.Object
+Evaluates to: false
+With type: java.lang.Boolean
+
+
+Expression: ${ null == "" }
+ExpectedType: class java.lang.Object
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${ null != "" }
+ExpectedType: class java.lang.Object
+Evaluates to: true
+With type: java.lang.Boolean
+
+Expression: ${ "" == null }
+ExpectedType: class java.lang.Object
+Evaluates to: false
+With type: java.lang.Boolean
+
+Expression: ${ "" != null }
+ExpectedType: class java.lang.Object
+Evaluates to: true
+With type: java.lang.Boolean
+
+
+#######################################################
+# arithmetic operators involving Strings
+
+Expression: ${ 4 + 3 }
+ExpectedType: class java.lang.Object
+Evaluates to: 7
+With type: java.lang.Long
+
+Expression: ${ 4.0 + 3 }
+ExpectedType: class java.lang.Object
+Evaluates to: 7.0
+With type: java.lang.Double
+
+Expression: ${ 4 + 3.0 }
+ExpectedType: class java.lang.Object
+Evaluates to: 7.0
+With type: java.lang.Double
+
+Expression: ${ 4.0 + 3.0 }
+ExpectedType: class java.lang.Object
+Evaluates to: 7.0
+With type: java.lang.Double
+
+Expression: ${ "4" + 3 }
+ExpectedType: class java.lang.Object
+Evaluates to: 7
+With type: java.lang.Long
+
+Expression: ${ "4.0" + 3 }
+ExpectedType: class java.lang.Object
+Evaluates to: 7.0
+With type: java.lang.Double
+
+Expression: ${ "4" + 3.0 }
+ExpectedType: class java.lang.Object
+Evaluates to: 7.0
+With type: java.lang.Double
+
+Expression: ${ "4.0" + 3.0 }
+ExpectedType: class java.lang.Object
+Evaluates to: 7.0
+With type: java.lang.Double
+
+Expression: ${ 4 + "3" }
+ExpectedType: class java.lang.Object
+Evaluates to: 7
+With type: java.lang.Long
+
+Expression: ${ 4.0 + "3" }
+ExpectedType: class java.lang.Object
+Evaluates to: 7.0
+With type: java.lang.Double
+
+Expression: ${ 4 + "3.0" }
+ExpectedType: class java.lang.Object
+Evaluates to: 7.0
+With type: java.lang.Double
+
+Expression: ${ 4.0 + "3.0" }
+ExpectedType: class java.lang.Object
+Evaluates to: 7.0
+With type: java.lang.Double
+
+Expression: ${ "4" + "3" }
+ExpectedType: class java.lang.Object
+Evaluates to: 7
+With type: java.lang.Long
+
+Expression: ${ "4.0" + "3" }
+ExpectedType: class java.lang.Object
+Evaluates to: 7.0
+With type: java.lang.Double
+
+Expression: ${ "4" + "3.0" }
+ExpectedType: class java.lang.Object
+Evaluates to: 7.0
+With type: java.lang.Double
+
+Expression: ${ "4.0" + "3.0" }
+ExpectedType: class java.lang.Object
+Evaluates to: 7.0
+With type: java.lang.Double
+
+
+
+Expression: ${ 4 - 3 }
+ExpectedType: class java.lang.Object
+Evaluates to: 1
+With type: java.lang.Long
+
+Expression: ${ 4.0 - 3 }
+ExpectedType: class java.lang.Object
+Evaluates to: 1.0
+With type: java.lang.Double
+
+Expression: ${ 4 - 3.0 }
+ExpectedType: class java.lang.Object
+Evaluates to: 1.0
+With type: java.lang.Double
+
+Expression: ${ 4.0 - 3.0 }
+ExpectedType: class java.lang.Object
+Evaluates to: 1.0
+With type: java.lang.Double
+
+Expression: ${ "4" - 3 }
+ExpectedType: class java.lang.Object
+Evaluates to: 1
+With type: java.lang.Long
+
+Expression: ${ "4.0" - 3 }
+ExpectedType: class java.lang.Object
+Evaluates to: 1.0
+With type: java.lang.Double
+
+Expression: ${ "4" - 3.0 }
+ExpectedType: class java.lang.Object
+Evaluates to: 1.0
+With type: java.lang.Double
+
+Expression: ${ "4.0" - 3.0 }
+ExpectedType: class java.lang.Object
+Evaluates to: 1.0
+With type: java.lang.Double
+
+Expression: ${ 4 - "3" }
+ExpectedType: class java.lang.Object
+Evaluates to: 1
+With type: java.lang.Long
+
+Expression: ${ 4.0 - "3" }
+ExpectedType: class java.lang.Object
+Evaluates to: 1.0
+With type: java.lang.Double
+
+Expression: ${ 4 - "3.0" }
+ExpectedType: class java.lang.Object
+Evaluates to: 1.0
+With type: java.lang.Double
+
+Expression: ${ 4.0 - "3.0" }
+ExpectedType: class java.lang.Object
+Evaluates to: 1.0
+With type: java.lang.Double
+
+Expression: ${ "4" - "3" }
+ExpectedType: class java.lang.Object
+Evaluates to: 1
+With type: java.lang.Long
+
+Expression: ${ "4.0" - "3" }
+ExpectedType: class java.lang.Object
+Evaluates to: 1.0
+With type: java.lang.Double
+
+Expression: ${ "4" - "3.0" }
+ExpectedType: class java.lang.Object
+Evaluates to: 1.0
+With type: java.lang.Double
+
+Expression: ${ "4.0" - "3.0" }
+ExpectedType: class java.lang.Object
+Evaluates to: 1.0
+With type: java.lang.Double
+
+
+
+Expression: ${ 4 * 3 }
+ExpectedType: class java.lang.Object
+Evaluates to: 12
+With type: java.lang.Long
+
+Expression: ${ 4.0 * 3 }
+ExpectedType: class java.lang.Object
+Evaluates to: 12.0
+With type: java.lang.Double
+
+Expression: ${ 4 * 3.0 }
+ExpectedType: class java.lang.Object
+Evaluates to: 12.0
+With type: java.lang.Double
+
+Expression: ${ 4.0 * 3.0 }
+ExpectedType: class java.lang.Object
+Evaluates to: 12.0
+With type: java.lang.Double
+
+Expression: ${ "4" * 3 }
+ExpectedType: class java.lang.Object
+Evaluates to: 12
+With type: java.lang.Long
+
+Expression: ${ "4.0" * 3 }
+ExpectedType: class java.lang.Object
+Evaluates to: 12.0
+With type: java.lang.Double
+
+Expression: ${ "4" * 3.0 }
+ExpectedType: class java.lang.Object
+Evaluates to: 12.0
+With type: java.lang.Double
+
+Expression: ${ "4.0" * 3.0 }
+ExpectedType: class java.lang.Object
+Evaluates to: 12.0
+With type: java.lang.Double
+
+Expression: ${ 4 * "3" }
+ExpectedType: class java.lang.Object
+Evaluates to: 12
+With type: java.lang.Long
+
+Expression: ${ 4.0 * "3" }
+ExpectedType: class java.lang.Object
+Evaluates to: 12.0
+With type: java.lang.Double
+
+Expression: ${ 4 * "3.0" }
+ExpectedType: class java.lang.Object
+Evaluates to: 12.0
+With type: java.lang.Double
+
+Expression: ${ 4.0 * "3.0" }
+ExpectedType: class java.lang.Object
+Evaluates to: 12.0
+With type: java.lang.Double
+
+Expression: ${ "4" * "3" }
+ExpectedType: class java.lang.Object
+Evaluates to: 12
+With type: java.lang.Long
+
+Expression: ${ "4.0" * "3" }
+ExpectedType: class java.lang.Object
+Evaluates to: 12.0
+With type: java.lang.Double
+
+Expression: ${ "4" * "3.0" }
+ExpectedType: class java.lang.Object
+Evaluates to: 12.0
+With type: java.lang.Double
+
+Expression: ${ "4.0" * "3.0" }
+ExpectedType: class java.lang.Object
+Evaluates to: 12.0
+With type: java.lang.Double
+
+
+
+Expression: ${ 4 / 3 }
+ExpectedType: class java.lang.Object
+Evaluates to: 1.3333333333333333
+With type: java.lang.Double
+
+Expression: ${ 4.0 / 3 }
+ExpectedType: class java.lang.Object
+Evaluates to: 1.3333333333333333
+With type: java.lang.Double
+
+Expression: ${ 4 / 3.0 }
+ExpectedType: class java.lang.Object
+Evaluates to: 1.3333333333333333
+With type: java.lang.Double
+
+Expression: ${ 4.0 / 3.0 }
+ExpectedType: class java.lang.Object
+Evaluates to: 1.3333333333333333
+With type: java.lang.Double
+
+Expression: ${ "4" / 3 }
+ExpectedType: class java.lang.Object
+Evaluates to: 1.3333333333333333
+With type: java.lang.Double
+
+Expression: ${ "4.0" / 3 }
+ExpectedType: class java.lang.Object
+Evaluates to: 1.3333333333333333
+With type: java.lang.Double
+
+Expression: ${ "4" / 3.0 }
+ExpectedType: class java.lang.Object
+Evaluates to: 1.3333333333333333
+With type: java.lang.Double
+
+Expression: ${ "4.0" / 3.0 }
+ExpectedType: class java.lang.Object
+Evaluates to: 1.3333333333333333
+With type: java.lang.Double
+
+Expression: ${ 4 / "3" }
+ExpectedType: class java.lang.Object
+Evaluates to: 1.3333333333333333
+With type: java.lang.Double
+
+Expression: ${ 4.0 / "3" }
+ExpectedType: class java.lang.Object
+Evaluates to: 1.3333333333333333
+With type: java.lang.Double
+
+Expression: ${ 4 / "3.0" }
+ExpectedType: class java.lang.Object
+Evaluates to: 1.3333333333333333
+With type: java.lang.Double
+
+Expression: ${ 4.0 / "3.0" }
+ExpectedType: class java.lang.Object
+Evaluates to: 1.3333333333333333
+With type: java.lang.Double
+
+Expression: ${ "4" / "3" }
+ExpectedType: class java.lang.Object
+Evaluates to: 1.3333333333333333
+With type: java.lang.Double
+
+Expression: ${ "4.0" / "3" }
+ExpectedType: class java.lang.Object
+Evaluates to: 1.3333333333333333
+With type: java.lang.Double
+
+Expression: ${ "4" / "3.0" }
+ExpectedType: class java.lang.Object
+Evaluates to: 1.3333333333333333
+With type: java.lang.Double
+
+Expression: ${ "4.0" / "3.0" }
+ExpectedType: class java.lang.Object
+Evaluates to: 1.3333333333333333
+With type: java.lang.Double
+
+
+
+Expression: ${ 4 % 3 }
+ExpectedType: class java.lang.Object
+Evaluates to: 1
+With type: java.lang.Long
+
+Expression: ${ 4.0 % 3 }
+ExpectedType: class java.lang.Object
+Evaluates to: 1.0
+With type: java.lang.Double
+
+Expression: ${ 4 % 3.0 }
+ExpectedType: class java.lang.Object
+Evaluates to: 1.0
+With type: java.lang.Double
+
+Expression: ${ 4.0 % 3.0 }
+ExpectedType: class java.lang.Object
+Evaluates to: 1.0
+With type: java.lang.Double
+
+Expression: ${ "4" % 3 }
+ExpectedType: class java.lang.Object
+Evaluates to: 1
+With type: java.lang.Long
+
+Expression: ${ "4.0" % 3 }
+ExpectedType: class java.lang.Object
+Evaluates to: 1.0
+With type: java.lang.Double
+
+Expression: ${ "4" % 3.0 }
+ExpectedType: class java.lang.Object
+Evaluates to: 1.0
+With type: java.lang.Double
+
+Expression: ${ "4.0" % 3.0 }
+ExpectedType: class java.lang.Object
+Evaluates to: 1.0
+With type: java.lang.Double
+
+Expression: ${ 4 % "3" }
+ExpectedType: class java.lang.Object
+Evaluates to: 1
+With type: java.lang.Long
+
+Expression: ${ 4.0 % "3" }
+ExpectedType: class java.lang.Object
+Evaluates to: 1.0
+With type: java.lang.Double
+
+Expression: ${ 4 % "3.0" }
+ExpectedType: class java.lang.Object
+Evaluates to: 1.0
+With type: java.lang.Double
+
+Expression: ${ 4.0 % "3.0" }
+ExpectedType: class java.lang.Object
+Evaluates to: 1.0
+With type: java.lang.Double
+
+Expression: ${ "4" % "3" }
+ExpectedType: class java.lang.Object
+Evaluates to: 1
+With type: java.lang.Long
+
+Expression: ${ "4.0" % "3" }
+ExpectedType: class java.lang.Object
+Evaluates to: 1.0
+With type: java.lang.Double
+
+Expression: ${ "4" % "3.0" }
+ExpectedType: class java.lang.Object
+Evaluates to: 1.0
+With type: java.lang.Double
+
+Expression: ${ "4.0" % "3.0" }
+ExpectedType: class java.lang.Object
+Evaluates to: 1.0
+With type: java.lang.Double
+
+
+
+Expression: ${ "8" / "2" }
+ExpectedType: class java.lang.Object
+Evaluates to: 4.0
+With type: java.lang.Double
+
+Expression: ${ "4e2" + "3" }
+ExpectedType: class java.lang.Object
+Evaluates to: 403.0
+With type: java.lang.Double
+
+Expression: ${ "4" + "3e2" }
+ExpectedType: class java.lang.Object
+Evaluates to: 304.0
+With type: java.lang.Double
+
+Expression: ${ "4e2" + "3e2" }
+ExpectedType: class java.lang.Object
+Evaluates to: 700.0
+With type: java.lang.Double
+
+
+
+#######################################################
+# unary minus operator involving Strings
+
+Expression: ${ -3 }
+ExpectedType: class java.lang.Object
+Evaluates to: -3
+With type: java.lang.Long
+
+Expression: ${ -3.0 }
+ExpectedType: class java.lang.Object
+Evaluates to: -3.0
+With type: java.lang.Double
+
+Expression: ${ -"3" }
+ExpectedType: class java.lang.Object
+Evaluates to: -3
+With type: java.lang.Long
+
+Expression: ${ -"3.0" }
+ExpectedType: class java.lang.Object
+Evaluates to: -3.0
+With type: java.lang.Double
+
+Expression: ${ -"3e2" }
+ExpectedType: class java.lang.Object
+Evaluates to: -300.0
+With type: java.lang.Double
+
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/test/parserTests.txt b/standard/src/org/apache/taglibs/standard/lang/jstl/test/parserTests.txt
new file mode 100644
index 0000000..405afd1
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/test/parserTests.txt
@@ -0,0 +1,148 @@
+# testing mixture of strings and expressions
+abc
+${ 3}
+a${
+a${ 5 }
+${ 3 }b
+${ 1 }${ 2 }
+abc ${ 1} ${ 2} def
+
+# testing values that end with or contain "$"
+$
+\$
+  $  
+test$
+$test
+test$test
+test$$$
+test$$${ 34 }
+test$$${ 34 }$$
+test$${ 34 }
+$${ 34 }
+$$
+test$$
+test$$test
+${ 34 }$${ 34 }
+
+# literals
+${1}
+${-12}
+${true}
+${false}
+${null}
+${4.2}
+${-21.3}
+${4.}
+${.21}
+${3e-1}
+${.2222222222}
+
+# string literals with "
+${"abc"}
+${""}
+${"a"}
+${"         "}
+${" some string ''' "}
+${" with escaping \\"}
+${" with escaping \""}
+${" with escaping \"\\\""}
+${" bad \ escaping"}
+${" bad \' escaping"}
+
+# string literals with '
+${'abc'}
+${''}
+${'a'}
+${'         '}
+${' some string """ '}
+${' with escaping \\'}
+${' with escaping \''}
+${' with escaping \'\\\''}
+${' bad \ escaping'}
+${' bad \" escaping'}
+
+# identifiers
+${abc}
+${abc123}
+${abc_123}
+${bad*identifier}
+
+# property accessors
+${a .b .c}
+${ abc . 'def.ghi' . ghi . "jkl \"" }
+
+# array accessors
+${ a[14] }
+${ abc [def]}
+${ def ["yesthisisallowed"]}
+
+# mixed property/array accessors
+${ a.b.c[d. e.  f]}
+${ a[14].b[32].c[24][ 261] [24]}
+${ a[b[c[d[e[f]]]].g] }
+
+# mixed operators
+${ 1 + 3 - 2 * 1 == 4}
+${ 1 + 3 - 2 * 1 == 4 / 1.2}
+${ 1 + 3 - 2 * 1 == 4 / 1.2 and abc}
+${ 1 + 3 - 2 * 1 == 4 / 1.2 and abc or def or ghi and true}
+
+# unary operators
+${ --not abc.def }
+
+# array accessors of non-integer types
+${  a ["hello"]."12" [17.5] }
+
+# making sure unicode escapes are not recognized
+\u0040
+"\u0040"
+
+# relational operators
+${ a > b }
+${ a gt b }
+${ a < b }
+${ a lt b }
+${ a >= b }
+${ a ge b }
+${ a <= b }
+${ a le b }
+${ a == b }
+${ a eq b }
+${ a != b }
+${ a ne b }
+
+# logical operators
+${ a and b}
+${ a && b}
+${ a or b}
+${ a || b}
+${ !a }
+${ not a }
+
+# empty operator
+${ empty "A"}
+${ empty "" }
+${ empty null }
+${ empty false}
+${ empty 0}
+${ not empty 0}
+${ not empty empty 0}
+${ empty }
+
+# functions
+#${a()}
+#${ a() }
+#${a(b)}
+#${ a(b) }
+#${a(b,c)}
+#${a(b,c,d)}
+#${a:b(c)}
+#${a:b(c,d)}
+#${a:b(c,d,e)}
+#${a(b).c}
+#${a(b)[c]}
+#${a[b()]}
+
+# non-ascii input - the parser automatically translates the @@non-ascii
+# into a UNICODE string with value \u1111
+@@non-ascii
diff --git a/standard/src/org/apache/taglibs/standard/lang/jstl/test/parserTestsOutput.txt b/standard/src/org/apache/taglibs/standard/lang/jstl/test/parserTestsOutput.txt
new file mode 100644
index 0000000..b06dfa6
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/jstl/test/parserTestsOutput.txt
@@ -0,0 +1,260 @@
+# testing mixture of strings and expressions
+Attribute value: abc
+Parses to: abc
+Attribute value: ${ 3}
+Parses to: ${3}
+Attribute value: a${
+Causes an error: An error occurred while parsing custom action attribute "test" with value "a${": Encountered "<EOF>", expected one of [<INTEGER_LITERAL>, <FLOATING_POINT_LITERAL>, <STRING_LITERAL>, "true", "false", "null", "(", "-", "not", "!", "empty", <IDENTIFIER>]
+Attribute value: a${ 5 }
+Parses to: a${5}
+Attribute value: ${ 3 }b
+Parses to: ${3}b
+Attribute value: ${ 1 }${ 2 }
+Parses to: ${1}${2}
+Attribute value: abc ${ 1} ${ 2} def
+Parses to: abc ${1} ${2} def
+
+# testing values that end with or contain "$"
+Attribute value: $
+Parses to: $
+Attribute value: \$
+Parses to: \$
+Attribute value:   $  
+Parses to:   $  
+Attribute value: test$
+Parses to: test$
+Attribute value: $test
+Parses to: $test
+Attribute value: test$test
+Parses to: test$test
+Attribute value: test$$$
+Parses to: test$$$
+Attribute value: test$$${ 34 }
+Parses to: test$$${34}
+Attribute value: test$$${ 34 }$$
+Parses to: test$$${34}$$
+Attribute value: test$${ 34 }
+Parses to: test$${34}
+Attribute value: $${ 34 }
+Parses to: $${34}
+Attribute value: $$
+Parses to: $$
+Attribute value: test$$
+Parses to: test$$
+Attribute value: test$$test
+Parses to: test$$test
+Attribute value: ${ 34 }$${ 34 }
+Parses to: ${34}$${34}
+
+# literals
+Attribute value: ${1}
+Parses to: ${1}
+Attribute value: ${-12}
+Parses to: ${(- 12)}
+Attribute value: ${true}
+Parses to: ${true}
+Attribute value: ${false}
+Parses to: ${false}
+Attribute value: ${null}
+Parses to: ${null}
+Attribute value: ${4.2}
+Parses to: ${4.2}
+Attribute value: ${-21.3}
+Parses to: ${(- 21.3)}
+Attribute value: ${4.}
+Parses to: ${4.0}
+Attribute value: ${.21}
+Parses to: ${0.21}
+Attribute value: ${3e-1}
+Parses to: ${0.3}
+Attribute value: ${.2222222222}
+Parses to: ${0.2222222222}
+
+# string literals with "
+Attribute value: ${"abc"}
+Parses to: ${"abc"}
+Attribute value: ${""}
+Parses to: ${""}
+Attribute value: ${"a"}
+Parses to: ${"a"}
+Attribute value: ${"         "}
+Parses to: ${"         "}
+Attribute value: ${" some string ''' "}
+Parses to: ${" some string ''' "}
+Attribute value: ${" with escaping \\"}
+Parses to: ${" with escaping \\"}
+Attribute value: ${" with escaping \""}
+Parses to: ${" with escaping \""}
+Attribute value: ${" with escaping \"\\\""}
+Parses to: ${" with escaping \"\\\""}
+Attribute value: ${" bad \ escaping"}
+Causes an error: An error occurred while parsing custom action attribute "test" with value "${" bad \ escaping"}": Encountered "" bad \ ", expected one of [<INTEGER_LITERAL>, <FLOATING_POINT_LITERAL>, <STRING_LITERAL>, "true", "false", "null", "(", "-", "not", "!", "empty", <IDENTIFIER>]
+Attribute value: ${" bad \' escaping"}
+Causes an error: An error occurred while parsing custom action attribute "test" with value "${" bad \' escaping"}": Encountered "" bad \'", expected one of [<INTEGER_LITERAL>, <FLOATING_POINT_LITERAL>, <STRING_LITERAL>, "true", "false", "null", "(", "-", "not", "!", "empty", <IDENTIFIER>]
+
+# string literals with '
+Attribute value: ${'abc'}
+Parses to: ${"abc"}
+Attribute value: ${''}
+Parses to: ${""}
+Attribute value: ${'a'}
+Parses to: ${"a"}
+Attribute value: ${'         '}
+Parses to: ${"         "}
+Attribute value: ${' some string """ '}
+Parses to: ${" some string \"\"\" "}
+Attribute value: ${' with escaping \\'}
+Parses to: ${" with escaping \\"}
+Attribute value: ${' with escaping \''}
+Parses to: ${" with escaping '"}
+Attribute value: ${' with escaping \'\\\''}
+Parses to: ${" with escaping '\\'"}
+Attribute value: ${' bad \ escaping'}
+Causes an error: An error occurred while parsing custom action attribute "test" with value "${' bad \ escaping'}": Encountered "' bad \ ", expected one of [<INTEGER_LITERAL>, <FLOATING_POINT_LITERAL>, <STRING_LITERAL>, "true", "false", "null", "(", "-", "not", "!", "empty", <IDENTIFIER>]
+Attribute value: ${' bad \" escaping'}
+Causes an error: An error occurred while parsing custom action attribute "test" with value "${' bad \" escaping'}": Encountered "' bad \"", expected one of [<INTEGER_LITERAL>, <FLOATING_POINT_LITERAL>, <STRING_LITERAL>, "true", "false", "null", "(", "-", "not", "!", "empty", <IDENTIFIER>]
+
+# identifiers
+Attribute value: ${abc}
+Parses to: ${abc}
+Attribute value: ${abc123}
+Parses to: ${abc123}
+Attribute value: ${abc_123}
+Parses to: ${abc_123}
+Attribute value: ${bad*identifier}
+Parses to: ${(bad * identifier)}
+
+# property accessors
+Attribute value: ${a .b .c}
+Parses to: ${a.b.c}
+Attribute value: ${ abc . 'def.ghi' . ghi . "jkl \"" }
+Causes an error: An error occurred while parsing custom action attribute "test" with value "${ abc . 'def.ghi' . ghi . "jkl \"" }": Encountered "'def.ghi'", expected one of [<IDENTIFIER>]
+
+# array accessors
+Attribute value: ${ a[14] }
+Parses to: ${a[14]}
+Attribute value: ${ abc [def]}
+Parses to: ${abc[def]}
+Attribute value: ${ def ["yesthisisallowed"]}
+Parses to: ${def["yesthisisallowed"]}
+
+# mixed property/array accessors
+Attribute value: ${ a.b.c[d. e.  f]}
+Parses to: ${a.b.c[d.e.f]}
+Attribute value: ${ a[14].b[32].c[24][ 261] [24]}
+Parses to: ${a[14].b[32].c[24][261][24]}
+Attribute value: ${ a[b[c[d[e[f]]]].g] }
+Parses to: ${a[b[c[d[e[f]]]].g]}
+
+# mixed operators
+Attribute value: ${ 1 + 3 - 2 * 1 == 4}
+Parses to: ${((1 + 3 - (2 * 1)) == 4)}
+Attribute value: ${ 1 + 3 - 2 * 1 == 4 / 1.2}
+Parses to: ${((1 + 3 - (2 * 1)) == (4 / 1.2))}
+Attribute value: ${ 1 + 3 - 2 * 1 == 4 / 1.2 and abc}
+Parses to: ${(((1 + 3 - (2 * 1)) == (4 / 1.2)) and abc)}
+Attribute value: ${ 1 + 3 - 2 * 1 == 4 / 1.2 and abc or def or ghi and true}
+Parses to: ${((((1 + 3 - (2 * 1)) == (4 / 1.2)) and abc) or def or (ghi and true))}
+
+# unary operators
+Attribute value: ${ --not abc.def }
+Parses to: ${(- - not abc.def)}
+
+# array accessors of non-integer types
+Attribute value: ${  a ["hello"]."12" [17.5] }
+Causes an error: An error occurred while parsing custom action attribute "test" with value "${  a ["hello"]."12" [17.5] }": Encountered ""12"", expected one of [<IDENTIFIER>]
+
+# making sure unicode escapes are not recognized
+Attribute value: \u0040
+Parses to: \u0040
+Attribute value: "\u0040"
+Parses to: "\u0040"
+
+# relational operators
+Attribute value: ${ a > b }
+Parses to: ${(a > b)}
+Attribute value: ${ a gt b }
+Parses to: ${(a > b)}
+Attribute value: ${ a < b }
+Parses to: ${(a < b)}
+Attribute value: ${ a lt b }
+Parses to: ${(a < b)}
+Attribute value: ${ a >= b }
+Parses to: ${(a >= b)}
+Attribute value: ${ a ge b }
+Parses to: ${(a >= b)}
+Attribute value: ${ a <= b }
+Parses to: ${(a <= b)}
+Attribute value: ${ a le b }
+Parses to: ${(a <= b)}
+Attribute value: ${ a == b }
+Parses to: ${(a == b)}
+Attribute value: ${ a eq b }
+Parses to: ${(a == b)}
+Attribute value: ${ a != b }
+Parses to: ${(a != b)}
+Attribute value: ${ a ne b }
+Parses to: ${(a != b)}
+
+# logical operators
+Attribute value: ${ a and b}
+Parses to: ${(a and b)}
+Attribute value: ${ a && b}
+Parses to: ${(a and b)}
+Attribute value: ${ a or b}
+Parses to: ${(a or b)}
+Attribute value: ${ a || b}
+Parses to: ${(a or b)}
+Attribute value: ${ !a }
+Parses to: ${(not a)}
+Attribute value: ${ not a }
+Parses to: ${(not a)}
+
+# empty operator
+Attribute value: ${ empty "A"}
+Parses to: ${(empty "A")}
+Attribute value: ${ empty "" }
+Parses to: ${(empty "")}
+Attribute value: ${ empty null }
+Parses to: ${(empty null)}
+Attribute value: ${ empty false}
+Parses to: ${(empty false)}
+Attribute value: ${ empty 0}
+Parses to: ${(empty 0)}
+Attribute value: ${ not empty 0}
+Parses to: ${(not empty 0)}
+Attribute value: ${ not empty empty 0}
+Parses to: ${(not empty empty 0)}
+Attribute value: ${ empty }
+Causes an error: An error occurred while parsing custom action attribute "test" with value "${ empty }": Encountered "}", expected one of [<INTEGER_LITERAL>, <FLOATING_POINT_LITERAL>, <STRING_LITERAL>, "true", "false", "null", "(", "-", "not", "!", "empty", <IDENTIFIER>]
+
+# functions
+Attribute value: ${a()}
+Parses to: ${a()}
+Attribute value: ${ a() }
+Parses to: ${a()}
+Attribute value: ${a(b)}
+Parses to: ${a(b)}
+Attribute value: ${ a(b) }
+Parses to: ${a(b)}
+Attribute value: ${a(b,c)}
+Parses to: ${a(b, c)}
+Attribute value: ${a(b,c,d)}
+Parses to: ${a(b, c, d)}
+Attribute value: ${a:b(c)}
+Parses to: ${a:b(c)}
+Attribute value: ${a:b(c,d)}
+Parses to: ${a:b(c, d)}
+Attribute value: ${a:b(c,d,e)}
+Parses to: ${a:b(c, d, e)}
+Attribute value: ${a(b).c}
+Parses to: ${a(b).c}
+Attribute value: ${a(b)[c]}
+Parses to: ${a(b)[c]}
+Attribute value: ${a[b()]}
+Parses to: ${a[b()]}
+
+# non-ascii input - the parser automatically translates the @@non-ascii
+# into a UNICODE string with value \u1111
+Attribute value: ?
+Parses to: ?
diff --git a/standard/src/org/apache/taglibs/standard/lang/support/ExpressionEvaluator.java b/standard/src/org/apache/taglibs/standard/lang/support/ExpressionEvaluator.java
new file mode 100644
index 0000000..99339ce
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/support/ExpressionEvaluator.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.support;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.PageContext;
+import javax.servlet.jsp.tagext.Tag;
+
+/**
+ * <p>The interface for an expression-language validator and evaluator.
+ * Classes that implement an expression language expose their functionality
+ * via this interface.</p>
+ *
+ * <p>The validate() and evaluate() methods must be thread-safe.  That is,
+ * multiple threads may call these methods on the same ExpressionEvaluator
+ * object simultaneously.  Implementations should synchronize access if
+ * they depend on transient state.  Implementations should not, however,
+ * assume that only one object of each ExpressionEvaluator type will be
+ * instantiated; global caching should therefore be static.  No release()
+ * mechanism or robust lifecycle is specified, for language-interpreter
+ * pluggability is experimental in EA2.</p>
+ *
+ * <p><b>WARNING</b>:  This class supports experimentation for the EA2
+ * release of JSTL; it is not expected to be part of the final RI or
+ * specification.</p>
+ *
+ * @author Shawn Bayern (based exactly on rev1 draft)
+ */
+public interface ExpressionEvaluator {
+
+    /** 
+     * Translation time validation of an expression. 
+     * This method will return a null String if the expression 
+     * is valid; otherwise an error message. 
+     */ 
+    public String validate(String attributeName, 
+                           String expression); 
+
+    /** 
+     * Evaluates the expression at request time. 
+     */ 
+    public Object evaluate(String attributeName, 
+                           String expression, 
+                           Class expectedType, 
+                           Tag tag, 
+                           PageContext pageContext) 
+       throws JspException; 
+} 
diff --git a/standard/src/org/apache/taglibs/standard/lang/support/ExpressionEvaluatorManager.java b/standard/src/org/apache/taglibs/standard/lang/support/ExpressionEvaluatorManager.java
new file mode 100644
index 0000000..5deb066
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/lang/support/ExpressionEvaluatorManager.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.lang.support;
+
+import java.util.HashMap;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.PageContext;
+import javax.servlet.jsp.tagext.Tag;
+
+import org.apache.taglibs.standard.lang.jstl.Coercions;
+import org.apache.taglibs.standard.lang.jstl.ELException;
+import org.apache.taglibs.standard.lang.jstl.Logger;
+
+/**
+ * <p>A conduit to the JSTL EL.  Based on...</p>
+ * 
+ * <p>An implementation of the ExpressionEvaluatorManager called for by
+ * the JSTL rev1 draft.  This class is responsible for delegating a
+ * request for expression evaluating to the particular, "active"
+ * ExpressionEvaluator for the given point in the PageContext object
+ * passed in.</p>
+ *
+ * @author Shawn Bayern
+ */
+public class ExpressionEvaluatorManager { 
+
+    //*********************************************************************
+    // Constants
+
+    public static final String EVALUATOR_CLASS =
+        "org.apache.taglibs.standard.lang.jstl.Evaluator";
+    // private static final String EVALUATOR_PARAMETER =
+    //    "javax.servlet.jsp.jstl.temp.ExpressionEvaluatorClass";
+
+    //*********************************************************************
+    // Internal, static state
+
+    private static HashMap nameMap = new HashMap();
+    private static Logger logger = new Logger(System.out);
+
+    //*********************************************************************
+    // Public static methods
+
+    /** 
+     * Invokes the evaluate() method on the "active" ExpressionEvaluator
+     * for the given pageContext.
+     */ 
+    public static Object evaluate(String attributeName, 
+                                  String expression, 
+                                  Class expectedType, 
+                                  Tag tag, 
+                                  PageContext pageContext) 
+           throws JspException
+    {
+
+        // the evaluator we'll use
+        ExpressionEvaluator target = getEvaluatorByName(EVALUATOR_CLASS);
+
+        // delegate the call
+        return (target.evaluate(
+            attributeName, expression, expectedType, tag, pageContext));
+    }
+
+    /** 
+     * Invokes the evaluate() method on the "active" ExpressionEvaluator
+     * for the given pageContext.
+     */ 
+    public static Object evaluate(String attributeName, 
+                                  String expression, 
+                                  Class expectedType, 
+                                  PageContext pageContext) 
+           throws JspException
+    {
+
+        // the evaluator we'll use
+        ExpressionEvaluator target = getEvaluatorByName(EVALUATOR_CLASS);
+
+        // delegate the call
+        return (target.evaluate(
+            attributeName, expression, expectedType, null, pageContext));
+    }
+
+    /**
+     * Gets an ExpressionEvaluator from the cache, or seeds the cache
+     * if we haven't seen a particular ExpressionEvaluator before.
+     */
+    public static
+	    ExpressionEvaluator getEvaluatorByName(String name)
+            throws JspException {
+
+        Object oEvaluator = nameMap.get(name);
+        if (oEvaluator != null) {
+            return ((ExpressionEvaluator) oEvaluator);
+        }
+        try {
+            synchronized (nameMap) {
+                oEvaluator = nameMap.get(name);
+                if (oEvaluator != null) {
+                    return ((ExpressionEvaluator) oEvaluator);
+                }
+                ExpressionEvaluator e = (ExpressionEvaluator)
+                    Class.forName(name).newInstance();
+                nameMap.put(name, e);
+                return (e);
+            }
+        } catch (ClassCastException ex) {
+            // just to display a better error message
+            throw new JspException("invalid ExpressionEvaluator: " +
+                ex.toString(), ex);
+        } catch (ClassNotFoundException ex) {
+            throw new JspException("couldn't find ExpressionEvaluator: " +
+                ex.toString(), ex);
+        } catch (IllegalAccessException ex) {
+            throw new JspException("couldn't access ExpressionEvaluator: " +
+                ex.toString(), ex);
+        } catch (InstantiationException ex) {
+            throw new JspException(
+                "couldn't instantiate ExpressionEvaluator: " +
+                ex.toString(), ex);
+        }
+    }
+
+    /** Performs a type conversion according to the EL's rules. */
+    public static Object coerce(Object value, Class classe)
+            throws JspException {
+	try {
+	    // just delegate the call
+	    return Coercions.coerce(value, classe, logger);
+	} catch (ELException ex) {
+	    throw new JspException(ex);
+	}
+    }
+
+} 
diff --git a/standard/src/org/apache/taglibs/standard/resources/Resources.java b/standard/src/org/apache/taglibs/standard/resources/Resources.java
new file mode 100644
index 0000000..bffc6e5
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/resources/Resources.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.resources;
+
+import java.text.MessageFormat;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+/**
+ * <p>Provides locale-neutral access to string resources.  Only the
+ * documentation and code are in English. :-)
+ *
+ * <p>The major goal, aside from globalization, is convenience.
+ * Access to resources with no parameters is made in the form:</p>
+ * <pre>
+ *     Resources.getMessage(MESSAGE_NAME);
+ * </pre>
+ *
+ * <p>Access to resources with one parameter works like</p>
+ * <pre>
+ *     Resources.getMessage(MESSAGE_NAME, arg1);
+ * </pre>
+ *
+ * <p>... and so on.</p>
+ *
+ * @author Shawn Bayern
+ */
+public class Resources {
+
+    //*********************************************************************
+    // Static data
+
+    /** The location of our resources. */
+    private static final String RESOURCE_LOCATION
+	= "org.apache.taglibs.standard.resources.Resources";
+
+    /** Our class-wide ResourceBundle. */
+    private static ResourceBundle rb =
+	ResourceBundle.getBundle(RESOURCE_LOCATION);
+
+
+    //*********************************************************************
+    // Public static methods
+
+    /** Retrieves a message with no arguments. */
+    public static String getMessage(String name)
+	    throws MissingResourceException {
+	return rb.getString(name);
+    }
+
+    /** Retrieves a message with arbitrarily many arguments. */
+    public static String getMessage(String name, Object[] a)
+	    throws MissingResourceException {
+	String res = rb.getString(name);
+	return MessageFormat.format(res, a);
+    }
+
+    /** Retrieves a message with one argument. */
+    public static String getMessage(String name, Object a1)
+	    throws MissingResourceException {
+	return getMessage(name, new Object[] { a1 });
+    }
+
+    /** Retrieves a message with two arguments. */
+    public static String getMessage(String name, Object a1, Object a2)
+	    throws MissingResourceException {
+	return getMessage(name, new Object[] { a1, a2 });
+    }
+
+    /** Retrieves a message with three arguments. */
+    public static String getMessage(String name,
+				    Object a1,
+				    Object a2,
+				    Object a3)
+	    throws MissingResourceException {
+	return getMessage(name, new Object[] { a1, a2, a3 });
+    }
+
+    /** Retrieves a message with four arguments. */
+    public static String getMessage(String name,
+			 	    Object a1,
+				    Object a2,
+				    Object a3,
+				    Object a4)
+	    throws MissingResourceException {
+	return getMessage(name, new Object[] { a1, a2, a3, a4 });
+    }
+
+    /** Retrieves a message with five arguments. */
+    public static String getMessage(String name,
+				    Object a1,
+				    Object a2,
+				    Object a3,
+				    Object a4,
+				    Object a5)
+	    throws MissingResourceException {
+	return getMessage(name, new Object[] { a1, a2, a3, a4, a5 });
+    }
+
+    /** Retrieves a message with six arguments. */
+    public static String getMessage(String name,
+				    Object a1,
+				    Object a2,
+				    Object a3,
+				    Object a4,
+				    Object a5,
+				    Object a6)
+	    throws MissingResourceException {
+	return getMessage(name, new Object[] { a1, a2, a3, a4, a5, a6 });
+    }
+
+}
diff --git a/standard/src/org/apache/taglibs/standard/resources/Resources.properties b/standard/src/org/apache/taglibs/standard/resources/Resources.properties
new file mode 100644
index 0000000..2bee781
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/resources/Resources.properties
@@ -0,0 +1,304 @@
+#########################################################################
+# Conventions:
+# - For error messages from particular tags, the resource should
+#     - (a) have a name beginning with TAGNAME_
+#     - (b) contain the name of the tag within the message
+# - Generic tag messages -- i.e., those used in more than one tag --
+#   should begin with TAG_
+# - Errors for TagLibraryValidators should begin with TLV_
+#########################################################################
+
+
+#########################################################################
+# Generic tag error messages
+#########################################################################
+
+TAG_NULL_ATTRIBUTE=\
+    The "{0}" attribute illegally evaluated to "null" or "" in <{1}>
+
+#########################################################################
+# Specific tag error messages
+#########################################################################
+
+# CORE
+
+CHOOSE_EXCLUSIVITY=\
+    Only one (or is it two?) <choose> subtag may evaluate its body
+
+EXPR_BAD_VALUE=\
+    In <expr>, attribute value="{0}" didn't evaluate successfully, \
+    but there was no "default" attribute and no non-whitespace content \
+    for the tag.
+
+FOREACH_STEP_NO_RESULTSET=\
+    Step cannot be > 1 when iterating over a ResultSet with <forEach>
+
+FOREACH_BAD_ITEMS=\
+    Don't know how to iterate over supplied "items" in <forEach>
+
+IMPORT_BAD_RELATIVE=\
+    In URL tags, when the "context" attribute is specified, \
+    values of both "context" and "url" must start with "/".
+
+IMPORT_REL_WITHOUT_HTTP=\
+    Relative <import> from non-HTTP request not allowed
+    
+IMPORT_REL_WITHOUT_DISPATCHER=\
+    Unable to get RequestDispatcher for Context: "{0}" and URL: "{1}". \
+    Verify values and/or enable cross context access.
+
+IMPORT_IO=\
+    I/O error in <import> occurred reading "{0}"
+
+IMPORT_ILLEGAL_STREAM=\
+    Unexpected internal error during <import&gt: \
+    Target servlet called getWriter(), then getOutputStream()
+
+IMPORT_ILLEGAL_WRITER=\
+    Unexpected internal error during <import&gt: \
+    Target servlet called getOutputStream(), then getWriter()
+
+#IMPORT_ILLEGAL_GETSTRING=\
+#    Unexpected internal error during <import&gt: \
+#    Target servlet called neither getOutputStream() nor getWriter()
+
+PARAM_OUTSIDE_PARENT=\
+    <param> outside <import> or <urlEncode>
+
+PARAM_ENCODE_BOOLEAN=\
+    In <param>, "encode" must be "true" or "false".  Got "{0}" instead.
+
+SET_BAD_SCOPE=\
+    Invalid "scope" attribute for <set>:  "{0}"
+
+SET_INVALID_PROPERTY=\
+    Invalid property in <set>:  "{0}"
+
+SET_INVALID_TARGET=\
+    Attempt to set the property of an invalid object in <set>.
+
+SET_NO_VALUE=\
+    Need either non-whitespace body or "value" attribute in <set>
+
+URLENCODE_NO_VALUE=\
+    Need either non-whitespace body or "value" attribute in <urlEncode>
+
+WHEN_OUTSIDE_CHOOSE=\
+    Illegal use of <when>-style tag without <choose> as its \
+    direct parent
+
+# I18N
+
+LOCALE_NO_LANGUAGE=\
+    Missing language component in 'value' attribute in <setLocale> 
+
+LOCALE_EMPTY_COUNTRY=\
+    Empty country component in 'value' attribute in <setLocale>
+
+PARAM_OUTSIDE_MESSAGE=\
+    <param> outside <message>
+
+MESSAGE_NO_KEY=\
+    <message> needs 'key' attribute or non-whitespace body
+
+FORMAT_NUMBER_INVALID_TYPE=\
+    In <formatNumber>, invalid 'type' attribute: "{0}"
+
+FORMAT_NUMBER_NO_VALUE=\
+    <formatNumber> needs 'value' attribute or non-whitespace body
+
+FORMAT_NUMBER_PARSE_ERROR=\
+    In <formatNumber>, 'value' attribute can not be parsed into java.lang.Number: "{0}"
+
+FORMAT_NUMBER_CURRENCY_ERROR=\
+    In <formatNumber>, unable to set currency
+
+PARSE_NUMBER_INVALID_TYPE=\
+    In <parseNumber>, invalid 'type' attribute: "{0}"
+
+PARSE_NUMBER_NO_VALUE=\
+    <parseNumber> needs 'value' attribute or non-whitespace body
+
+PARSE_NUMBER_NO_PARSE_LOCALE=\
+    In <parseNumber>, a parse locale can not be established
+
+PARSE_NUMBER_PARSE_ERROR=\
+    In <parseNumber>, 'value' attribute can not be parsed: "{0}"
+
+FORMAT_DATE_INVALID_TYPE=\
+    In <formatDate>, invalid 'type' attribute: "{0}"
+
+FORMAT_DATE_BAD_TIMEZONE=\
+    In <formatDate>, 'timeZone' must be an instance of java.lang.String or java.util.TimeZone
+
+FORMAT_DATE_INVALID_DATE_STYLE=\
+    In <formatDate>, invalid 'dateStyle' attribute: "{0}"
+
+FORMAT_DATE_INVALID_TIME_STYLE=\
+    In <formatDate>, invalid 'timeStyle' attribute: "{0}"
+
+PARSE_DATE_INVALID_TYPE=\
+    In <parseDate>, invalid 'type' attribute: "{0}"
+
+PARSE_DATE_BAD_TIMEZONE=\
+    In <parseDate>, 'timeZone' must be an instance of java.lang.String or java.util.TimeZone
+
+PARSE_DATE_INVALID_DATE_STYLE=\
+    In <parseDate>, invalid 'dateStyle' attribute: "{0}"
+
+PARSE_DATE_INVALID_TIME_STYLE=\
+    In <parseDate>, invalid 'timeStyle' attribute: "{0}"
+
+PARSE_DATE_NO_VALUE=\
+    <parseDate> needs 'value' attribute or non-whitespace body
+
+PARSE_DATE_PARSE_ERROR=\
+    In <parseDate>, 'value' attribute can not be parsed: "{0}"
+
+PARSE_DATE_NO_PARSE_LOCALE=\
+    In <parseDate>, a parse locale can not be established
+
+# SQL
+
+DRIVER_INVALID_CLASS=\
+    In <driver>, invalid driver class name: "{0}"
+
+DATASOURCE_INVALID=\
+    Unable to get connection, DataSource invalid: "{0}"
+ 
+JDBC_PARAM_COUNT=\
+    Invalid number of JDBC parameters specified.
+
+PARAM_BAD_VALUE=\
+    Invalid or out of bounds value specified in parameter.
+ 
+TRANSACTION_NO_SUPPORT=\
+    In <transaction>, datasource does not support transactions
+
+TRANSACTION_COMMIT_ERROR=\
+    In <transaction>, error committing transaction: "{0}"
+
+TRANSACTION_INVALID_ISOLATION=\
+    In <transaction>, invalid transaction isolation
+
+NOT_SUPPORTED=\
+    Not supported
+
+ERROR_GET_CONNECTION=\
+    Error getting connection: "{0}"
+
+ERROR_NESTED_DATASOURCE=\
+    It is illegal to specify a DataSource when nested within a <transaction>
+
+SQL_PARAM_OUTSIDE_PARENT=\
+    <param> or <dateParam> must be subtag of SQLExecutionTag actions like <query> or <update>
+
+SQL_NO_STATEMENT=\
+    No SQL statement specified
+
+SQL_PROCESS_ERROR=\
+    Error processing SQL: "{0}"
+
+SQL_DATASOURCE_INVALID_TYPE=\
+    'dataSource' is neither a String nor a javax.sql.DataSource
+
+SQL_DATASOURCE_NULL=\
+    'dataSource' is null
+
+SQL_MAXROWS_PARSE_ERROR=\
+    Error parsing 'javax.servlet.jsp.jstl.sql.maxRows' configuration setting: "{0}"
+
+SQL_MAXROWS_INVALID=\
+    'javax.servlet.jsp.jstl.sql.maxRows' configuration setting neither an Integer nor a String
+
+SQL_DATE_PARAM_INVALID_TYPE=\
+    In <dateParam>, invalid 'type' attribute: "{0}"
+
+# XML
+
+FOREACH_NOT_NODESET=\
+    <forEach> can't iterate over XPath expressions that don't return a node-set
+
+PARAM_NO_VALUE=\
+    <param> needs 'value' attribute or non-whitespace body
+
+PARAM_OUTSIDE_TRANSFORM=\
+    <param> outside <transform>
+
+PARSE_INVALID_SOURCE=\
+    Unrecognized object supplied as 'xml' attribute to <parse>
+
+PARSE_NO_SAXTRANSFORMER=\
+    Filter supplied to <parse>, but default TransformerFactory \
+    does not support SAX.
+
+TRANSFORM_NO_TRANSFORMER=\
+    <transform> was not passed an XSLT stylesheet
+
+TRANSFORM_SOURCE_INVALID_LIST=\
+    <transform> encountered an invalid java.util.List while processing 'xml' attribute.  This error is typically caused if you pass a node-set with more than one node to <transform>'s 'xml' attribute.
+
+TRANSFORM_SOURCE_UNRECOGNIZED=\
+    <transform> encountered an unknown type while processing 'xml' attribute
+
+TRANSFORM_XSLT_UNRECOGNIZED=\
+    <transform> encountered an unknown type while processing 'xslt' attribute
+
+UNABLE_TO_RESOLVE_ENTITY=\
+    Could not resolve entity reference: "{0}"
+
+#########################################################################
+# JSTL core TLV messages
+#########################################################################
+
+# Parameters 
+
+TLV_PARAMETER_ERROR=\
+    Invalid value for "{0}" validator parameter in TLD
+
+# Generic errors
+
+TLV_ILLEGAL_BODY=\
+    Encountered illegal body of tag "{0}" tag, given its attributes.
+
+TLV_MISSING_BODY=\
+    A body is necessary inside the "{0}" tag, given its attributes.
+
+TLV_ILLEGAL_CHILD_TAG=\
+    Illegal child tag in "{0}:{1}" tag: "{2}" tag
+
+TLV_ILLEGAL_TEXT_BODY=\
+    Illegal text inside "{0}:{1}" tag: "{2}...".
+
+TLV_INVALID_ATTRIBUTE=\
+    Invalid "{0}" attribute in "{1}" tag: "{2}"
+
+TLV_ILLEGAL_ORPHAN=\
+    Invalid use of "{0}" tag outside legitimate parent tag
+
+TLV_PARENT_WITHOUT_SUBTAG=\
+    Illegal "{0}" without child "{1}" tag
+
+# Errors customized to particular tags (sort of)  :-)
+
+TLV_ILLEGAL_ORDER=\
+    Illegal "{0}" after "{1}:{2}" tag in "{1}:{3}" tag.
+
+TLV_ILLEGAL_PARAM=\
+    Illegal "{0}:{1}" tag within "{0}:{2} {3}='...'" tag
+
+TLV_DANGLING_SCOPE=\
+    Illegal 'scope' attribute without 'var' in "{0}" tag.
+
+TLV_EMPTY_VAR=\
+    Empty 'var' attribute in "{0}" tag.
+
+SET_NO_SETTER_METHOD=No setter method in <set> for property "{0}"
+
+IMPORT_ABS_ERROR=Problem accessing the absolute URL "{0}". {1}
+
+XPATH_ERROR_EVALUATING_EXPR=Error evaluating XPath expression "{0}": {1}
+
+XPATH_ILLEGAL_ARG_EVALUATING_EXPR=Illegal argument evaluating XPath expression "{0}": {1}
+
+XPATH_ERROR_XOBJECT=Error accessing data in XObject: {0}
diff --git a/standard/src/org/apache/taglibs/standard/resources/Resources_ja.properties b/standard/src/org/apache/taglibs/standard/resources/Resources_ja.properties
new file mode 100644
index 0000000..8452ff8
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/resources/Resources_ja.properties
@@ -0,0 +1,297 @@
+#########################################################################
+# Conventions:
+# - For error messages from particular tags, the resource should
+#     - (a) have a name beginning with TAGNAME_
+#     - (b) contain the name of the tag within the message
+# - Generic tag messages -- i.e., those used in more than one tag --
+#   should begin with TAG_
+# - Errors for TagLibraryValidators should begin with TLV_
+#########################################################################
+
+
+#########################################################################
+# Generic tag error messages
+#########################################################################
+
+TAG_NULL_ATTRIBUTE=\
+    <{1}> \u5185\u306b\u3042\u308b "{0}" \u5c5e\u6027\u304c "null" \u3082\u3057\u304f\u306f "" \u3067\u3042\u308b\u3068\u4e0d\u6b63\u306b\u8a55\u4fa1\u3057\u307e\u3057\u305f\u3002
+
+#########################################################################
+# Specific tag error messages
+#########################################################################
+
+# CORE
+
+CHOOSE_EXCLUSIVITY=\
+    \uff11\u3064\u3057\u304b\u5b58\u5728\u306a\u3044 <choose> \u306e\u4e0b\u4f4d\u30bf\u30b0\u306f\u30dc\u30c7\u30a3\u306e\u4e2d\u8eab\u3092\u305d\u306e\u307e\u307e\u8a55\u4fa1\u3057\u307e\u3059
+
+EXPR_BAD_VALUE=\
+    <expr> \u5185\u3067\u3001\u5c5e\u6027\u5024="{0}" \u304c\u6b63\u3057\u304f\u8a55\u4fa1\u3055\u308c\u305a\u3001"default" \u5c5e\u6027\u3084\u30db\u30ef\u30a4\u30c8\u30b9\u30da\u30fc\u30b9\u306e\u306a\u3044\u30b3\u30f3\u30c6\u30f3\u30c4\u304c\u30bf\u30b0\u306e\u4e2d\u306b\u5b58\u5728\u3057\u307e\u305b\u3093
+
+FOREACH_STEP_NO_RESULTSET=\
+    <forEach> \u3067 ResultSet \u3092\u53cd\u5fa9\u51e6\u7406\u3057\u3088\u3046\u3068\u3057\u305f\u3068\u3053\u308d\u3001step \u306e\u5024\u3092 1 \u3088\u308a\u5927\u304d\u304f\u3059\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u305b\u3093
+
+FOREACH_BAD_ITEMS=\
+    <forEach> \u5185\u3067\u4f9b\u7d66\u3055\u308c\u305f "items" \u3092\u53cd\u5fa9\u51e6\u7406\u3059\u308b\u65b9\u6cd5\u304c\u4e0d\u660e\u3067\u3059
+
+IMPORT_BAD_RELATIVE=\
+    URL \u30bf\u30b0\u3067 "context" \u5c5e\u6027\u3092\u6307\u5b9a\u3059\u308b\u969b\u3001"context" \u304a\u3088\u3073 "url" \u306e\u4e21\u65b9\u306e\u5024\u306f "/" \u3067\u59cb\u307e\u3063\u3066\u3044\u306a\u3044\u3068\u3044\u3051\u307e\u305b\u3093
+
+IMPORT_REL_WITHOUT_HTTP=\
+    \u975e HTTP \u8981\u6c42\u3067\u306f\u3001URL\u3092\u76f8\u5bfe\u6307\u5b9a\u3059\u308b <import> \u3092\u8a31\u53ef\u3057\u3066\u3044\u307e\u305b\u3093
+
+IMPORT_REL_WITHOUT_DISPATCHER=\
+    Context: "{0}" \u304a\u3088\u3073 URL: "{1}" \u306b\u5bfe\u3057\u3066 RequestDispatcher \u3092\u53d6\u5f97\u3067\u304d\u307e\u305b\u3093\u3002\u6307\u5b9a\u3057\u305f\u5024\u3092\u78ba\u8a8d\u3059\u308b\u304b\u3001\u3082\u3057\u304f\u306f\u3001Context \u3092\u76f8\u4e92\u7684\u306b\u30a2\u30af\u30bb\u30b9\u3067\u304d\u308b\u3088\u3046\u306b\u3057\u3066\u304f\u3060\u3055\u3044
+
+IMPORT_IO=\
+    <import> \u3067\u3001"{0}" \u3092\u8aad\u307f\u8fbc\u307f\u4e2d\u306b\u5165\u51fa\u529b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f
+
+IMPORT_ILLEGAL_STREAM=\
+    <import&gt \u5185\u3067\u4e88\u671f\u305b\u306c\u5185\u90e8\u30a8\u30e9\u30fc: \u5bfe\u8c61\u3068\u306a\u3063\u305f Servlet \u3067 getWriter() \u30e1\u30bd\u30c3\u30c9\u304c\u547c\u3073\u51fa\u3055\u308c\u3066\u3044\u308b\u306e\u306b getOutputStream() \u30e1\u30bd\u30c3\u30c9\u3092\u547c\u3073\u51fa\u305d\u3046\u3068\u3057\u307e\u3057\u305f
+
+IMPORT_ILLEGAL_WRITER=\
+    <import&gt \u5185\u3067\u4e88\u671f\u305b\u306c\u5185\u90e8\u30a8\u30e9\u30fc: \u5bfe\u8c61\u3068\u306a\u3063\u305f Servlet \u3067 getOutputStream() \u30e1\u30bd\u30c3\u30c9\u304c\u547c\u3073\u51fa\u3055\u308c\u3066\u3044\u308b\u306e\u306b getWriter() \u30e1\u30bd\u30c3\u30c9\u3092\u547c\u3073\u51fa\u305d\u3046\u3068\u3057\u307e\u3057\u305f
+
+#IMPORT_ILLEGAL_GETSTRING=\
+#    Unexpected internal error during <import&gt: \
+#    Target servlet called neither getOutputStream() nor getWriter()
+
+PARAM_OUTSIDE_PARENT=\
+    <import> \u3082\u3057\u304f\u306f <urlEncode> \u306e\u5916\u5074\u306b <param> \u304c\u3042\u308a\u307e\u3059
+
+PARAM_ENCODE_BOOLEAN=\
+    <param> \u3067\u306f\u3001"encode" \u306f "true" \u3082\u3057\u304f\u306f "false" \u3067\u306a\u3044\u3068\u3044\u3051\u307e\u305b\u3093\u3002\u4ee3\u308f\u308a\u306b "{0}" \u3092\u53d6\u5f97\u3057\u307e\u3057\u305f
+
+SET_BAD_SCOPE=\
+    <set> \u306b\u5bfe\u3057\u3001\u7121\u52b9\u306a "scope" \u5c5e\u6027\u3067\u3059:  "{0}"
+
+SET_INVALID_PROPERTY=\
+    <set> \u306b\u5bfe\u3057\u3001\u7121\u52b9\u306a\u30d7\u30ed\u30d1\u30c6\u30a3\u3067\u3059:  "{0}"
+
+SET_INVALID_TARGET=\
+    <set> \u306b\u5bfe\u3057\u3001\u7121\u52b9\u306a\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306e\u30d7\u30ed\u30d1\u30c6\u30a3\u3092\u30bb\u30c3\u30c8\u3057\u3088\u3046\u3068\u3057\u3066\u3044\u307e\u3059
+
+SET_NO_VALUE=\
+    <set> \u3067\u306f\u3001\u30db\u30ef\u30a4\u30c8\u30b9\u30da\u30fc\u30b9\u306e\u306a\u3044\u30dc\u30c7\u30a3\u3082\u3057\u304f\u306f "value" \u5c5e\u6027\u304c\u5fc5\u8981\u3067\u3059
+
+URLENCODE_NO_VALUE=\
+    <urlEncode> \u3067\u306f\u3001\u30db\u30ef\u30a4\u30c8\u30b9\u30da\u30fc\u30b9\u306e\u306a\u3044\u30dc\u30c7\u30a3\u3082\u3057\u304f\u306f "value" \u5c5e\u6027\u304c\u5fc5\u8981\u3067\u3059
+
+WHEN_OUTSIDE_CHOOSE=\
+    \u76f4\u8fd1\u306e\u89aa\u30bf\u30b0\u3067\u3042\u308b <choose> \u3092\u30bb\u30c3\u30c8\u305b\u305a\u306b <when> \u30b9\u30bf\u30a4\u30eb\u30fb\u30bf\u30b0\u3092\u4f7f\u3046\u3053\u3068\u306f\u6b63\u3057\u304f\u3042\u308a\u307e\u305b\u3093
+
+# I18N
+
+LOCALE_NO_LANGUAGE=\
+    <setLocale> \u3067\u3001'value' \u5c5e\u6027\u306b\u6307\u5b9a\u3057\u305f\u8a00\u8a9e\u30b3\u30fc\u30c9\u304c\u307e\u3061\u304c\u3063\u3066\u3044\u307e\u3059
+
+LOCALE_EMPTY_COUNTRY=\
+    <setLocale> \u3067\u3001'value' \u5c5e\u6027\u306b\u6307\u5b9a\u3057\u305f\u56fd\u30b3\u30fc\u30c9\u304c\u5b58\u5728\u3057\u307e\u305b\u3093
+
+PARAM_OUTSIDE_MESSAGE=\
+    <message> \u306e\u5916\u5074\u306b <param> \u304c\u3042\u308a\u307e\u3059
+
+MESSAGE_NO_KEY=\
+    <message> \u3067\u306f 'key' \u5c5e\u6027\u3082\u3057\u304f\u306f\u30db\u30ef\u30a4\u30c8\u30b9\u30da\u30fc\u30b9\u306e\u306a\u3044\u30dc\u30c7\u30a3\u304c\u5fc5\u8981\u3067\u3059
+
+FORMAT_NUMBER_INVALID_TYPE=\
+    <formatNumber> \u3067\u3001\u7121\u52b9\u306a 'type' \u5c5e\u6027\u3067\u3059: "{0}"
+
+FORMAT_NUMBER_NO_VALUE=\
+    <formatNumber> \u3067\u306f 'value' \u5c5e\u6027\u3082\u3057\u304f\u306f\u30db\u30ef\u30a4\u30c8\u30b9\u30da\u30fc\u30b9\u306e\u306a\u3044\u30dc\u30c7\u30a3\u304c\u5fc5\u8981\u3067\u3059
+
+FORMAT_NUMBER_PARSE_ERROR=\
+    <formatNumber> \u5185\u306b\u3042\u308b\u3001'value' \u5c5e\u6027\u3092 java.lang.Number \u578b\u3067\u89e3\u6790\u3067\u304d\u307e\u305b\u3093: "{0}"
+
+FORMAT_NUMBER_CURRENCY_ERROR=\
+    <formatNumber> \u3067\u3001\u901a\u8ca8\u30d5\u30a9\u30fc\u30de\u30c3\u30c8\u3092\u30bb\u30c3\u30c8\u3067\u304d\u307e\u305b\u3093
+
+PARSE_NUMBER_INVALID_TYPE=\
+    <parseNumber> \u3067\u3001\u7121\u52b9\u306a 'type' \u5c5e\u6027\u3067\u3059: "{0}"
+
+PARSE_NUMBER_NO_VALUE=\
+    <parseNumber> \u3067\u306f 'value' \u5c5e\u6027\u3082\u3057\u304f\u306f\u30db\u30ef\u30a4\u30c8\u30b9\u30da\u30fc\u30b9\u306e\u306a\u3044\u30dc\u30c7\u30a3\u304c\u5fc5\u8981\u3067\u3059
+
+PARSE_NUMBER_NO_PARSE_LOCALE=\
+    <parseNumber> \u5185\u3067\u3001\u89e3\u6790\u3055\u308c\u305f\u30ed\u30b1\u30fc\u30eb\u3092\u78ba\u5b9a\u3067\u304d\u307e\u305b\u3093
+
+PARSE_NUMBER_PARSE_ERROR=\
+    <parseNumber> \u5185\u306b\u3042\u308b\u3001'value' \u5c5e\u6027\u3092\u89e3\u6790\u3067\u304d\u307e\u305b\u3093: "{0}"
+
+FORMAT_DATE_INVALID_TYPE=\
+    <formatDate> \u3067\u3001\u7121\u52b9\u306a 'type' \u5c5e\u6027\u3067\u3059: "{0}"
+
+FORMAT_DATE_BAD_TIMEZONE=\
+    <formatDate> \u3067\u306f\u3001'timeZone' \u306f java.lang.String \u578b\u3082\u3057\u304f\u306f java.util.TimeZone \u578b\u306e\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u3067\u306a\u3044\u3068\u3044\u3051\u307e\u305b\u3093
+
+FORMAT_DATE_INVALID_DATE_STYLE=\
+    <formatDate> \u3067\u3001\u7121\u52b9\u306a 'dateStyle' \u5c5e\u6027\u3067\u3059: "{0}"
+
+FORMAT_DATE_INVALID_TIME_STYLE=\
+    <formatDate> \u3067\u3001\u7121\u52b9\u306a 'timeStyle' \u5c5e\u6027\u3067\u3059: "{0}"
+
+PARSE_DATE_INVALID_TYPE=\
+    <parseDate> \u3067\u3001\u7121\u52b9\u306a 'type' \u5c5e\u6027\u3067\u3059: "{0}"
+
+PARSE_DATE_BAD_TIMEZONE=\
+    <parseDate> \u5185\u306b\u3042\u308b\u3001'timeZone' \u306f java.lang.String \u578b\u3082\u3057\u304f\u306f java.util.TimeZone \u578b\u306e\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u3067\u306a\u3044\u3068\u3044\u3051\u307e\u305b\u3093
+
+PARSE_DATE_INVALID_DATE_STYLE=\
+    <parseDate> \u3067\u3001\u7121\u52b9\u306a 'dateStyle' \u5c5e\u6027\u3067\u3059: "{0}"
+
+PARSE_DATE_INVALID_TIME_STYLE=\
+    <parseDate> \u3067\u3001\u7121\u52b9\u306a 'timeStyle' \u5c5e\u6027\u3067\u3059: "{0}"
+
+PARSE_DATE_NO_VALUE=\
+    <parseDate> \u3067\u306f 'value' \u5c5e\u6027\u3082\u3057\u304f\u306f\u30db\u30ef\u30a4\u30c8\u30b9\u30da\u30fc\u30b9\u306e\u306a\u3044\u30dc\u30c7\u30a3\u304c\u5fc5\u8981\u3067\u3059
+
+PARSE_DATE_PARSE_ERROR=\
+    <parseDate> \u5185\u306b\u3042\u308b\u3001'value' \u5c5e\u6027\u3092\u89e3\u6790\u3067\u304d\u307e\u305b\u3093: "{0}"
+
+PARSE_DATE_NO_PARSE_LOCALE=\
+    <parseDate> \u5185\u3067\u3001\u89e3\u6790\u3055\u308c\u305f\u30ed\u30b1\u30fc\u30eb\u3092\u78ba\u5b9a\u3067\u304d\u307e\u305b\u3093
+
+# SQL
+
+DRIVER_INVALID_CLASS=\
+    <driver> \u3067\u3001\u7121\u52b9\u306a\u30c9\u30e9\u30a4\u30d0\u30fb\u30af\u30e9\u30b9\u540d\u3092\u6307\u5b9a\u3057\u307e\u3057\u305f: "{0}"
+
+DATASOURCE_INVALID=\
+    DataSource \u304c\u7121\u52b9\u3067\u3042\u308b\u305f\u3081\u3001Connection \u3092\u53d6\u5f97\u3067\u304d\u307e\u305b\u3093: "{0}"
+
+JDBC_PARAM_COUNT=\
+    \u6307\u5b9a\u3057\u305f JDBC \u306e\u30d1\u30e9\u30e1\u30fc\u30bf\u6570\u304c\u7121\u52b9\u3067\u3059
+
+PARAM_BAD_VALUE=\
+    \u30d1\u30e9\u30e1\u30fc\u30bf\u3067\u6307\u5b9a\u3057\u305f\u5024\u304c\u7121\u52b9\u3067\u3042\u308b\u304b\u7bc4\u56f2\u5916\u3067\u3059
+
+TRANSACTION_NO_SUPPORT=\
+    <transaction> \u5185\u306b\u3042\u308b\u3001DataSource \u306f\u30c8\u30e9\u30f3\u30b6\u30af\u30b7\u30e7\u30f3\u3092\u30b5\u30dd\u30fc\u30c8\u3057\u3066\u3044\u307e\u305b\u3093
+
+TRANSACTION_COMMIT_ERROR=\
+    <transaction> \u306b\u304a\u3044\u3066\u3001\u30c8\u30e9\u30f3\u30b6\u30af\u30b7\u30e7\u30f3\u306e\u30b3\u30df\u30c3\u30c8\u6642\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f: "{0}"
+
+TRANSACTION_INVALID_ISOLATION=\
+    <transaction> \u306b\u304a\u3044\u3066\u3001\u7121\u52b9\u306a\u30c8\u30e9\u30f3\u30b6\u30af\u30b7\u30e7\u30f3\u906e\u65ad\u30ec\u30d9\u30eb\u3092\u6307\u5b9a\u3057\u307e\u3057\u305f
+
+NOT_SUPPORTED=\
+    \u30b5\u30dd\u30fc\u30c8\u3057\u3066\u3044\u307e\u305b\u3093
+
+ERROR_GET_CONNECTION=\
+    Connection \u306e\u53d6\u5f97\u6642\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f: "{0}"
+
+ERROR_NESTED_DATASOURCE=\
+    <transaction> \u306e\u4e2d\u3067\u5165\u308c\u5b50\u3068\u306a\u3063\u305f\u30c7\u30fc\u30bf\u30bd\u30fc\u30b9\u3092\u6307\u5b9a\u3059\u308b\u3053\u3068\u306f\u4e0d\u6b63\u3067\u3059
+
+SQL_PARAM_OUTSIDE_PARENT=\
+    <param> \u307e\u305f\u306f <dateParam> \u306f <query> \u3082\u3057\u304f\u306f <update> \u306e\u3088\u3046\u306b SQLExecutionTag \u547d\u4ee4\u306e\u4e0b\u4f4d\u30bf\u30b0\u3067\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093
+
+SQL_NO_STATEMENT=\
+    SQL \u30b9\u30c6\u30fc\u30c8\u30e1\u30f3\u30c8\u304c\u6307\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093
+
+SQL_PROCESS_ERROR=\
+    SQL \u306e\u51e6\u7406\u6642\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f: "{0}"
+
+SQL_DATASOURCE_INVALID_TYPE=\
+    'dataSource' \u304c String \u578b \u3067\u3082 javax.sql.DataSource \u578b\u306e\u3069\u3061\u3089\u3067\u3082\u3042\u308a\u307e\u305b\u3093
+
+SQL_DATASOURCE_NULL=\
+    'dataSource' \u304c null \u3067\u3059
+
+SQL_MAXROWS_PARSE_ERROR=\
+    'javax.servlet.jsp.jstl.sql.maxRows' \u306e\u74b0\u5883\u8a2d\u5b9a\u3067\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f: "{0}"
+
+SQL_MAXROWS_INVALID=\
+    'javax.servlet.jsp.jstl.sql.maxRows' \u3067\u74b0\u5883\u8a2d\u5b9a\u3057\u305f\u5024\u306f Integer \u578b \u3067\u3082 String \u578b\u306e\u3069\u3061\u3089\u3067\u3082\u3042\u308a\u307e\u305b\u3093
+
+SQL_DATE_PARAM_INVALID_TYPE=\
+    <dateParam> \u3067\u3001\u7121\u52b9\u306a 'type' \u5c5e\u6027\u3067\u3059: "{0}"
+
+# XML
+
+FOREACH_NOT_NODESET=\
+    \u30ce\u30fc\u30c9\u30bb\u30c3\u30c8\u306e\u8fd4\u3055\u308c\u306a\u3044 XPath \u8868\u73fe\u306b\u5bfe\u3057 <forEach> \u306f\u53cd\u5fa9\u51e6\u7406\u3059\u308b\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093
+
+PARAM_NO_VALUE=\
+    <param> \u3067\u306f 'value' \u5c5e\u6027\u3082\u3057\u304f\u306f\u30db\u30ef\u30a4\u30c8\u30b9\u30da\u30fc\u30b9\u306e\u306a\u3044\u30dc\u30c7\u30a3\u304c\u5fc5\u8981\u3067\u3059
+
+PARAM_OUTSIDE_TRANSFORM=\
+    <transform> \u306e\u5916\u5074\u306b <param> \u304c\u3042\u308a\u307e\u3059
+
+PARSE_INVALID_SOURCE=\
+    <parse> \u306b\u5bfe\u3057 'xml' \u5c5e\u6027\u3068\u3057\u3066\u4f9b\u7d66\u3057\u305f\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u3092\u8a8d\u8b58\u3067\u304d\u307e\u305b\u3093
+
+PARSE_NO_SAXTRANSFORMER=\
+    <parse> \u306b\u5bfe\u3057\u30d5\u30a3\u30eb\u30bf\u30fc\u304c\u4f9b\u7d66\u3055\u308c\u307e\u3057\u305f\u304c\u3001\u30c7\u30d5\u30a9\u30eb\u30c8\u306e TransformerFactory \u304c SAX \u3092\u30b5\u30dd\u30fc\u30c8\u3057\u3066\u3044\u307e\u305b\u3093
+
+TRANSFORM_NO_TRANSFORMER=\
+    <transform> \u306b\u5bfe\u3057 XSLT \u30b9\u30bf\u30a4\u30eb\u30b7\u30fc\u30c8\u304c\u901a\u308a\u307e\u305b\u3093
+
+TRANSFORM_SOURCE_INVALID_LIST=\
+    <transform> \u5185\u3067 'xml' \u5c5e\u6027\u306e\u51e6\u7406\u4e2d\u306b\u7121\u52b9\u306a java.util.List \u3068\u906d\u9047\u3057\u307e\u3057\u305f\u3002\u3053\u308c\u306f\u3001<transform> \u5185\u306e 'xml' \u5c5e\u6027\u306b\u5bfe\u3057\u3066 1 \u4ee5\u4e0a\u306e\u30ce\u30fc\u30c9\u3067\u69cb\u6210\u3055\u308c\u308b\u30ce\u30fc\u30c9\u30bb\u30c3\u30c8\u3092\u901a\u3055\u306a\u3044\u5834\u5408\u306b\u767a\u751f\u3059\u308b\u5178\u578b\u7684\u306a\u30a8\u30e9\u30fc\u3067\u3059
+
+TRANSFORM_SOURCE_UNRECOGNIZED=\
+    <transform> \u5185\u3067 'xml' \u5c5e\u6027\u306e\u51e6\u7406\u4e2d\u306b\u672a\u77e5\u306e\u578b\u3068\u906d\u9047\u3057\u307e\u3057\u305f
+
+TRANSFORM_XSLT_UNRECOGNIZED=\
+    <transform> \u5185\u3067 'xslt' \u5c5e\u6027\u306e\u51e6\u7406\u4e2d\u306b\u672a\u77e5\u306e\u578b\u3068\u906d\u9047\u3057\u307e\u3057\u305f
+
+UNABLE_TO_RESOLVE_ENTITY=\
+    \u30a8\u30f3\u30c6\u30a3\u30c6\u30a3\u53c2\u7167\u3092\u89e3\u6c7a\u3067\u304d\u307e\u305b\u3093: "{0}"
+
+#########################################################################
+# JSTL core TLV messages
+#########################################################################
+
+# Parameters
+
+TLV_PARAMETER_ERROR=\
+    TLD \u306b\u3088\u308b\u3068 "{0}" \u6709\u52b9\u30d1\u30e9\u30e1\u30fc\u30bf\u306b\u5bfe\u5fdc\u3059\u308b\u5024\u304c\u7121\u52b9\u3067\u3059
+
+# Generic errors
+
+TLV_ILLEGAL_BODY=\
+    \u5c5e\u6027\u3092\u6307\u5b9a\u3057\u307e\u3057\u305f\u304c\u3001"{0}" \u30bf\u30b0\u3067\u4e0d\u6b63\u306a\u30dc\u30c7\u30a3\u306b\u906d\u9047\u3057\u307e\u3057\u305f
+
+TLV_MISSING_BODY=\
+    \u5c5e\u6027\u3092\u6307\u5b9a\u3057\u307e\u3057\u305f\u304c\u3001\u30dc\u30c7\u30a3\u306f "{0}" \u30bf\u30b0\u306e\u4e2d\u306b\u5fc5\u8981\u3067\u3059
+
+TLV_ILLEGAL_CHILD_TAG=\
+    "{0}:{1}" \u30bf\u30b0\u306b\u4e0d\u6b63\u306a\u4e0b\u4f4d\u30bf\u30b0\u304c\u3042\u308a\u307e\u3059: "{2}" \u30bf\u30b0
+
+TLV_ILLEGAL_TEXT_BODY=\
+    "{0}:{1}" \u30bf\u30b0\u306e\u4e2d\u306b\u4e0d\u6b63\u306a\u30c6\u30ad\u30b9\u30c8\u304c\u3042\u308a\u307e\u3059: "{2}...".
+
+TLV_INVALID_ATTRIBUTE=\
+    "{1}" \u306b\u7121\u52b9\u306a "{0}" \u5c5e\u6027\u304c\u3042\u308a\u307e\u3059: "{2}"
+
+TLV_ILLEGAL_ORPHAN=\
+    \u9069\u5207\u306a\u89aa\u30bf\u30b0\u306e\u5916\u5074\u306b\u3042\u308b "{0}" \u30bf\u30b0\u306e\u4f7f\u3044\u65b9\u306f\u6b63\u3057\u304f\u3042\u308a\u307e\u305b\u3093
+
+TLV_PARENT_WITHOUT_SUBTAG=\
+    \u4e0b\u4f4d\u3067\u3042\u308b "{1}" \u30bf\u30b0\u306e\u306a\u3044 "{0}" \u306f\u6b63\u3057\u304f\u3042\u308a\u307e\u305b\u3093
+
+# Errors customized to particular tags (sort of)  :-)
+
+TLV_ILLEGAL_ORDER=\
+    "{1}:{3}" \u30bf\u30b0\u3067\u306f\u3001"{1}:{2}" \u30bf\u30b0\u306e\u5f8c\u306b\u3042\u308b "{0}" \u306f\u6b63\u3057\u304f\u3042\u308a\u307e\u305b\u3093
+
+TLV_ILLEGAL_PARAM=\
+    "{0}:{2} {3}='...'" \u30bf\u30b0\u306e\u4e2d\u306b\u3042\u308b "{0}:{1}" \u30bf\u30b0\u306f\u6b63\u3057\u304f\u3042\u308a\u307e\u305b\u3093
+
+TLV_DANGLING_SCOPE=\
+    "{0}" \u30bf\u30b0\u3067 'var' \u304c\u5b58\u5728\u3057\u306a\u3044\u306e\u306b 'scope' \u5c5e\u6027\u3092\u6307\u5b9a\u3059\u308b\u3053\u3068\u306f\u6b63\u3057\u304f\u3042\u308a\u307e\u305b\u3093
+
+TLV_EMPTY_VAR=\
+    "{0}" \u30bf\u30b0\u3067 'var' \u5c5e\u6027\u304c\u7a7a\u3067\u3059
+
+SET_NO_SETTER_METHOD=\
+    <set> \u306b\u304a\u3044\u3066\u3001\u30d7\u30ed\u30d1\u30c6\u30a3 "{0}" \u306b\u5bfe\u5fdc\u3059\u308b setter \u30e1\u30bd\u30c3\u30c9\u304c\u5b58\u5728\u3057\u307e\u305b\u3093
+
+IMPORT_ABS_ERROR=Problem accessing the absolute URL "{0}". {1}
+
+XPATH_ERROR_EVALUATING_EXPR=Error evaluating XPath expression "{0}": {1}
+
+XPATH_ILLEGAL_ARG_EVALUATING_EXPR=Illegal argument evaluating XPath expression "{0}": {1}
+
+XPATH_ERROR_XOBJECT=Error accessing data in XObject: {0}
diff --git a/standard/src/org/apache/taglibs/standard/tag/common/core/CatchTag.java b/standard/src/org/apache/taglibs/standard/tag/common/core/CatchTag.java
new file mode 100644
index 0000000..9c240a1
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/common/core/CatchTag.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.common.core;
+
+import javax.servlet.jsp.PageContext;
+import javax.servlet.jsp.tagext.TagSupport;
+import javax.servlet.jsp.tagext.TryCatchFinally;
+
+/**
+ * <p>Tag handler for <catch> in JSTL 1.0.</p>
+ * 
+ * <p><catch> simply catches any Throwables that occur in its body
+ * and optionally exposes them.
+ *
+ * @author Shawn Bayern
+ */
+
+public class CatchTag extends TagSupport implements TryCatchFinally {
+
+    /*
+     * If all tags that I proposed were this simple, people might
+     * think I was just trying to avoid work.  :-)
+     */
+
+    //*********************************************************************
+    // Constructor and lifecycle management
+
+    // initialize inherited and local state
+    public CatchTag() {
+        super();
+        init();
+    }
+
+    // Releases any resources we may have (or inherit)
+    public void release() {
+        super.release();
+        init();
+    }
+
+    private void init() {
+        var = null;
+    }
+
+
+    //*********************************************************************
+    // Private state
+
+    private String var;                                 // tag attribute
+    private boolean caught;                             // internal status
+
+
+    //*********************************************************************
+    // Tag logic
+
+    public int doStartTag() {
+        caught = false;
+	return EVAL_BODY_INCLUDE;
+    }
+
+    public void doCatch(Throwable t) {
+        if (var != null)
+            pageContext.setAttribute(var, t, PageContext.PAGE_SCOPE);
+        caught = true;
+    }
+
+    public void doFinally() {
+        if (var != null && !caught)
+            pageContext.removeAttribute(var, PageContext.PAGE_SCOPE);
+    }
+
+
+    //*********************************************************************
+    // Attribute accessors
+
+    public void setVar(String var) {
+        this.var = var;
+    }
+
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/common/core/ChooseTag.java b/standard/src/org/apache/taglibs/standard/tag/common/core/ChooseTag.java
new file mode 100644
index 0000000..f5c22b4
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/common/core/ChooseTag.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.common.core;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.tagext.TagSupport;
+
+import org.apache.taglibs.standard.resources.Resources;
+
+/**
+ * <p>Tag handler for <choose> in JSTL.</p>
+ * 
+ * <p><choose> is a very simple tag that acts primarily as a container;
+ * it always includes its body and allows exactly one of its child
+ * <when> tags to run.  Since this tag handler doesn't have any
+ * attributes, it is common.core to both the rtexprvalue and expression-
+ * evaluating versions of the JSTL library.
+ *
+ * @author Shawn Bayern
+ */
+
+public class ChooseTag extends TagSupport {
+
+    //*********************************************************************
+    // Constructor and lifecycle management
+
+    // initialize inherited and local state
+    public ChooseTag() {
+        super();
+        init();
+    }
+
+    // Releases any resources we may have (or inherit)
+    public void release() {
+        super.release();
+        init();
+    }
+
+
+    //*********************************************************************
+    // Private state
+
+    private boolean subtagGateClosed;      // has one subtag already executed?
+
+
+    //*********************************************************************
+    // Public methods implementing exclusivity checks
+
+    /**
+     * Returns status indicating whether a subtag should run or not.
+     *
+     * @return <tt>true</tt> if the subtag should evaluate its condition
+     *         and decide whether to run, <tt>false</tt> otherwise.
+     */
+    public synchronized boolean gainPermission() {
+        return (!subtagGateClosed);
+    }
+
+    /**
+     * Called by a subtag to indicate that it plans to evaluate its
+     * body.
+     */
+    public synchronized void subtagSucceeded() {
+        if (subtagGateClosed)
+            throw new IllegalStateException(
+		Resources.getMessage("CHOOSE_EXCLUSIVITY"));
+        subtagGateClosed = true;
+    }
+
+
+    //*********************************************************************
+    // Tag logic
+
+    // always include body
+    public int doStartTag() throws JspException {
+        subtagGateClosed = false;	// when we start, no children have run
+        return EVAL_BODY_INCLUDE;
+    }
+
+
+    //*********************************************************************
+    // Private utility methods
+
+    private void init() {
+        subtagGateClosed = false;                          // reset flag
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/common/core/DeclareTag.java b/standard/src/org/apache/taglibs/standard/tag/common/core/DeclareTag.java
new file mode 100644
index 0000000..afc41aa
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/common/core/DeclareTag.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.common.core;
+
+import javax.servlet.jsp.tagext.TagSupport;
+
+/**
+ * <p>Tag handler for <declaregt; in JSTL.  This tag handler is
+ * essentially a runtime no-op as far as tag logic is concerned; the
+ * only important functionality of the tag is to expose a scripting
+ * variable for an existing scoped attribute.</p>
+ * 
+ * @author Shawn Bayern
+ */
+
+public class DeclareTag extends TagSupport {
+
+    /*
+     * We're not identical to TagSupport only because we need to
+     * accept an additional "type" attribute.
+     */
+    public void setType(String x) { }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/common/core/ForEachSupport.java b/standard/src/org/apache/taglibs/standard/tag/common/core/ForEachSupport.java
new file mode 100644
index 0000000..8e98559
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/common/core/ForEachSupport.java
@@ -0,0 +1,400 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.common.core;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.StringTokenizer;
+
+import javax.servlet.jsp.JspTagException;
+import javax.servlet.jsp.jstl.core.LoopTagSupport;
+
+import org.apache.taglibs.standard.resources.Resources;
+
+/**
+ * <p>Support for tag handlers for <forEach>, the core iteration
+ * tag in JSTL 1.0.  This class extends LoopTagSupport and provides
+ * ForEach-specific functionality.  The rtexprvalue library and the
+ * expression-evaluating library each have handlers that extend this
+ * class.</p>
+ *
+ * <p>Localized here is the logic for handling the veritable smorgasbord
+ * of types supported by <forEach>, including arrays,
+ * Collections, and others.  To see how the actual iteration is controlled,
+ * review the javax.servlet.jsp.jstl.core.LoopTagSupport class instead.
+ * </p>
+ *
+ * @see javax.servlet.jsp.jstl.core.LoopTagSupport
+ * @author Shawn Bayern
+ */
+
+public abstract class ForEachSupport extends LoopTagSupport {
+
+    //*********************************************************************
+    // Implementation overview
+
+    /*
+     * This particular handler is essentially a large switching mechanism
+     * to support the various types that the <forEach> tag handles.  The
+     * class is organized around the private ForEachIterator interface,
+     * which serves as the basis for relaying information to the iteration
+     * implementation we inherit from LoopTagSupport.
+     *
+     * We expect to receive our 'items' from one of our subclasses
+     * (presumably from the rtexprvalue or expression-evaluating libraries).
+     * If 'items' is missing, we construct an Integer[] array representing
+     * iteration indices, in line with the spec draft.  From doStartTag(),
+     * we analyze and 'digest' the data we're passed.  Then, we simply
+     * relay items as necessary to the iteration implementation that
+     * we inherit from LoopTagSupport.
+     */
+
+
+    //*********************************************************************
+    // Internal, supporting classes and interfaces
+
+    /*
+     * Acts as a focal point for converting the various types we support.
+     * It would have been ideal to use Iterator here except for one problem:
+     * Iterator.hasNext() and Iterator.next() can't throw the JspTagException
+     * we want to throw.  So instead, we'll encapsulate the hasNext() and
+     * next() methods we want to provide inside this local class.
+     * (Other implementations are more than welcome to implement hasNext()
+     * and next() explicitly, not in terms of a back-end supporting class.
+     * For the forEach tag handler, however, this class acts as a convenient
+     * organizational mechanism, for we support so many different classes.
+     * This encapsulation makes it easier to localize implementations
+     * in support of particular types -- e.g., changing the implementation
+     * of primitive-array iteration to wrap primitives only on request,
+     * instead of in advance, would involve changing only those methods that
+     * handle primitive arrays.
+     */
+    protected static interface ForEachIterator {
+        public boolean hasNext() throws JspTagException;
+        public Object next() throws JspTagException;
+    }
+
+    /*
+     * Simple implementation of ForEachIterator that adapts from
+     * an Iterator.  This is appropriate for cases where hasNext() and
+     * next() don't need to throw JspTagException.  Such cases are common.core.
+     */
+    protected class SimpleForEachIterator implements ForEachIterator {
+        private Iterator i;
+        public SimpleForEachIterator(Iterator i) {
+            this.i = i;
+        }
+        public boolean hasNext() {
+            return i.hasNext();
+        }
+        public Object next() {
+            return i.next();
+        }
+    }
+
+
+    //*********************************************************************
+    // ForEach-specifc state (protected)
+
+    protected ForEachIterator items;              // our 'digested' items
+    protected Object rawItems;                    // our 'raw' items
+
+
+    //*********************************************************************
+    // Iteration control methods (based on processed 'items' object)
+
+    // (We inherit semantics and Javadoc from LoopTagSupport.)
+
+    protected boolean hasNext() throws JspTagException {
+        return items.hasNext();
+    }
+
+    protected Object next() throws JspTagException {
+        return items.next();
+    }
+
+    protected void prepare() throws JspTagException {
+        // produce the right sort of ForEachIterator
+        if (rawItems != null) {
+            // extract an iterator over the 'items' we've got
+            items = supportedTypeForEachIterator(rawItems);
+        } else {
+            // no 'items', so use 'begin' and 'end'
+            items = beginEndForEachIterator();
+        }
+
+        /* ResultSet no more supported in <c:forEach>
+        // step must be 1 when ResultSet is passed in
+        if (rawItems instanceof ResultSet && step != 1)
+            throw new JspTagException(
+		Resources.getMessage("FOREACH_STEP_NO_RESULTSET"));
+        */
+    }
+
+
+    //*********************************************************************
+    // Tag logic and lifecycle management
+
+    // Releases any resources we may have (or inherit)
+    public void release() {
+        super.release();
+        items = null;
+        rawItems = null;
+    }
+
+
+    //*********************************************************************
+    // Private generation methods for the ForEachIterators we produce
+
+    /* Extracts a ForEachIterator given an object of a supported type. */
+    protected ForEachIterator supportedTypeForEachIterator(Object o)
+            throws JspTagException {
+
+        /*
+         * This is, of necessity, just a big, simple chain, matching in
+         * order.  Since we are passed on Object because of all the
+         * various types we support, we cannot rely on the language's
+         * mechanism for resolving overloaded methods.  (Method overloading
+         * resolves via early binding, so the type of the 'o' reference,
+         * not the type of the eventual value that 'o' references, is
+         * all that's available.)
+         *
+         * Currently, we 'match' on the object we have through an
+         * if/else chain that picks the first interface (or class match)
+         * found for an Object.
+         */
+
+        ForEachIterator items;
+
+        if (o instanceof Object[])
+            items = toForEachIterator((Object[]) o);
+        else if (o instanceof boolean[])
+            items = toForEachIterator((boolean[]) o);
+        else if (o instanceof byte[])
+            items = toForEachIterator((byte[]) o);
+        else if (o instanceof char[])
+            items = toForEachIterator((char[]) o);
+        else if (o instanceof short[])
+            items = toForEachIterator((short[]) o);
+        else if (o instanceof int[])
+            items = toForEachIterator((int[]) o);
+        else if (o instanceof long[])
+            items = toForEachIterator((long[]) o);
+        else if (o instanceof float[])
+            items = toForEachIterator((float[]) o);
+        else if (o instanceof double[])
+            items = toForEachIterator((double[]) o);
+        else if (o instanceof Collection)
+            items = toForEachIterator((Collection) o);
+        else if (o instanceof Iterator)
+            items = toForEachIterator((Iterator) o);
+        else if (o instanceof Enumeration)
+            items = toForEachIterator((Enumeration) o);
+        else if (o instanceof Map)
+            items = toForEachIterator((Map) o);
+        /*
+        else if (o instanceof ResultSet)
+            items = toForEachIterator((ResultSet) o);
+        */
+        else if (o instanceof String)
+            items = toForEachIterator((String) o);
+        else
+            items = toForEachIterator(o);
+
+        return (items);
+    }
+
+    /*
+     * Creates a ForEachIterator of Integers from 'begin' to 'end'
+     * in support of cases where our tag handler isn't passed an
+     * explicit collection over which to iterate.
+     */
+    private ForEachIterator beginEndForEachIterator() {
+        /*
+         * To plug into existing support, we need to keep 'begin', 'end',
+         * and 'step' as they are.  So we'll simply create an Integer[]
+         * from 0 to 'end', inclusive, and let the existing implementation
+         * handle the subsetting and stepping operations.  (Other than
+         * localizing the cost of creating this Integer[] to the start
+         * of the operation instead of spreading it out over the lifetime
+         * of the iteration, this implementation isn't worse than one that
+         * created new Integers() as needed from next().  Such an adapter
+         * to ForEachIterator could easily be written but, like I said,
+         * wouldn't provide much benefit.)
+         */
+        Integer[] ia = new Integer[end + 1];
+        for (int i = 0; i <= end; i++)
+            ia[i] = new Integer(i);
+        return new SimpleForEachIterator(Arrays.asList(ia).iterator());
+    }
+
+
+    //*********************************************************************
+    // Private conversion methods to handle the various types we support
+
+    // catch-all method whose invocation currently signals a 'matching error'
+    protected ForEachIterator toForEachIterator(Object o)
+            throws JspTagException {
+        throw new JspTagException(Resources.getMessage("FOREACH_BAD_ITEMS"));
+    }
+
+    // returns an iterator over an Object array (via List)
+    protected ForEachIterator toForEachIterator(Object[] a) {
+        return new SimpleForEachIterator(Arrays.asList(a).iterator());
+    }
+
+    // returns an iterator over a boolean[] array, wrapping items in Boolean
+    protected ForEachIterator toForEachIterator(boolean[] a) {
+        Boolean[] wrapped = new Boolean[a.length];
+        for (int i = 0; i < a.length; i++)
+            wrapped[i] = new Boolean(a[i]);
+        return new SimpleForEachIterator(Arrays.asList(wrapped).iterator());
+    }
+
+    // returns an iterator over a byte[] array, wrapping items in Byte
+    protected ForEachIterator toForEachIterator(byte[] a) {
+        Byte[] wrapped = new Byte[a.length];
+        for (int i = 0; i < a.length; i++)
+            wrapped[i] = new Byte(a[i]);
+        return new SimpleForEachIterator(Arrays.asList(wrapped).iterator());
+    }
+
+    // returns an iterator over a char[] array, wrapping items in Character
+    protected ForEachIterator toForEachIterator(char[] a) {
+        Character[] wrapped = new Character[a.length];
+        for (int i = 0; i < a.length; i++)
+            wrapped[i] = new Character(a[i]);
+        return new SimpleForEachIterator(Arrays.asList(wrapped).iterator());
+    }
+
+    // returns an iterator over a short[] array, wrapping items in Short
+    protected ForEachIterator toForEachIterator(short[] a) {
+        Short[] wrapped = new Short[a.length];
+        for (int i = 0; i < a.length; i++)
+            wrapped[i] = new Short(a[i]);
+        return new SimpleForEachIterator(Arrays.asList(wrapped).iterator());
+    }
+
+    // returns an iterator over an int[] array, wrapping items in Integer
+    protected ForEachIterator toForEachIterator(int[] a) {
+        Integer[] wrapped = new Integer[a.length];
+        for (int i = 0; i < a.length; i++)
+            wrapped[i] = new Integer(a[i]);
+        return new SimpleForEachIterator(Arrays.asList(wrapped).iterator());
+    }
+
+    // returns an iterator over a long[] array, wrapping items in Long
+    protected ForEachIterator toForEachIterator(long[] a) {
+        Long[] wrapped = new Long[a.length];
+        for (int i = 0; i < a.length; i++)
+            wrapped[i] = new Long(a[i]);
+        return new SimpleForEachIterator(Arrays.asList(wrapped).iterator());
+    }
+
+    // returns an iterator over a float[] array, wrapping items in Float
+    protected ForEachIterator toForEachIterator(float[] a) {
+        Float[] wrapped = new Float[a.length];
+        for (int i = 0; i < a.length; i++)
+            wrapped[i] = new Float(a[i]);
+        return new SimpleForEachIterator(Arrays.asList(wrapped).iterator());
+    }
+
+    // returns an iterator over a double[] array, wrapping items in Double
+    protected ForEachIterator toForEachIterator(double[] a) {
+        Double[] wrapped = new Double[a.length];
+        for (int i = 0; i < a.length; i++)
+            wrapped[i] = new Double(a[i]);
+        return new SimpleForEachIterator(Arrays.asList(wrapped).iterator());
+    }
+
+    // retrieves an iterator from a Collection
+    protected ForEachIterator toForEachIterator(Collection c) {
+        return new SimpleForEachIterator(c.iterator());
+    }
+
+    // simply passes an Iterator through...
+    protected ForEachIterator toForEachIterator(Iterator i) {
+        return new SimpleForEachIterator(i);
+    }
+
+    // converts an Enumeration to an Iterator via a local adapter
+    protected ForEachIterator toForEachIterator(Enumeration e) {
+
+        // local adapter
+        class EnumerationAdapter implements ForEachIterator {
+            private Enumeration e;
+            public EnumerationAdapter(Enumeration e) {
+                this.e = e;
+            }
+            public boolean hasNext() {
+                return e.hasMoreElements();
+            }
+            public Object next() {
+                return e.nextElement();
+            }
+        }
+
+        return new EnumerationAdapter(e);
+    }
+
+    // retrieves an iterator over the Map.Entry items in a Map
+    protected ForEachIterator toForEachIterator(Map m) {
+        return new SimpleForEachIterator(m.entrySet().iterator());
+    }
+
+    /* No more supported in JSTL. See interface Result instead.
+    // thinly wraps a ResultSet in an appropriate Iterator
+    protected ForEachIterator toForEachIterator(ResultSet rs)
+            throws JspTagException {
+
+        // local adapter
+        class ResultSetAdapter implements ForEachIterator {
+            private ResultSet rs;
+            public ResultSetAdapter(ResultSet rs) {
+                this.rs = rs;
+            }
+            public boolean hasNext() throws JspTagException {
+                try {
+                    return !(rs.isLast());      // dependent on JDBC 2.0
+                } catch (java.sql.SQLException ex) {
+                    throw new JspTagException(ex.getMessage());
+                }
+            }
+            public Object next() throws JspTagException {
+                try {
+                    rs.next();
+                    return rs;
+                } catch (java.sql.SQLException ex) {
+                    throw new JspTagException(ex.getMessage());
+                }
+            }
+        }
+
+        return new ResultSetAdapter(rs);
+    }
+    */
+
+    // tokenizes a String as a CSV and returns an iterator over it
+    protected ForEachIterator toForEachIterator(String s) {
+        StringTokenizer st = new StringTokenizer(s, ",");
+        return toForEachIterator(st);           // convert from Enumeration
+    }
+
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/common/core/ForTokensSupport.java b/standard/src/org/apache/taglibs/standard/tag/common/core/ForTokensSupport.java
new file mode 100644
index 0000000..2d2665d
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/common/core/ForTokensSupport.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.common.core;
+
+import java.util.StringTokenizer;
+
+import javax.servlet.jsp.JspTagException;
+import javax.servlet.jsp.jstl.core.LoopTagSupport;
+
+/**
+ * <p>Support for tag handlers for <forTokens>, the tokenizing
+ * iteration tag in JSTL 1.0.  This class extends LoopTagSupport and
+ * provides ForTokens-specific functionality.  The rtexprvalue and
+ * expression-evaluating libraries each have handlers that extend this
+ * class.</p>
+ *
+ * @see javax.servlet.jsp.jstl.core.LoopTagSupport
+ * @author Shawn Bayern
+ */
+
+public abstract class ForTokensSupport extends LoopTagSupport {
+
+    //*********************************************************************
+    // Implementation overview
+
+    /*
+     * This handler simply constructs a StringTokenizer based on its input
+     * and relays tokens to the iteration implementation that it inherits.
+     * The 'items' and 'delims' attributes are expected to be provided by
+     * a subtag (presumably in the rtexprvalue or expression-evaluating
+     * versions of the JSTL library).
+     */
+
+
+    //*********************************************************************
+    // ForEachTokens-specific state (protected)
+
+    protected String items;                       // 'items' attribute
+    protected String delims;                      // 'delims' attribute
+    protected StringTokenizer st;                 // digested tokenizer
+
+
+    //*********************************************************************
+    // Iteration control methods
+
+    /*
+     * These just create and use a StringTokenizer.
+     * We inherit semantics and Javadoc from LoopTagSupport.
+     */
+
+    protected void prepare() throws JspTagException {
+      st = new StringTokenizer(items, delims);
+    }
+
+    protected boolean hasNext() throws JspTagException {
+        return st.hasMoreElements();
+    }
+
+    protected Object next() throws JspTagException {
+        return st.nextElement();
+    }
+
+
+    //*********************************************************************
+    // Tag logic and lifecycle management
+
+
+    // Releases any resources we may have (or inherit)
+    public void release() {
+        super.release();
+        items = delims = null;
+        st = null;
+    }
+
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/common/core/ImportSupport.java b/standard/src/org/apache/taglibs/standard/tag/common/core/ImportSupport.java
new file mode 100644
index 0000000..e51ef7e
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/common/core/ImportSupport.java
@@ -0,0 +1,552 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.common.core;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.io.UnsupportedEncodingException;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.Locale;
+
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpServletResponseWrapper;
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.JspTagException;
+import javax.servlet.jsp.PageContext;
+import javax.servlet.jsp.tagext.BodyTagSupport;
+import javax.servlet.jsp.tagext.TryCatchFinally;
+
+import org.apache.taglibs.standard.resources.Resources;
+
+/**
+ * <p>Support for tag handlers for <import>, the general-purpose
+ * text-importing mechanism for JSTL 1.0.  The rtexprvalue and expression-
+ * evaluating libraries each have handlers that extend this class.</p>
+ *
+ * @author Shawn Bayern
+ */
+
+public abstract class ImportSupport extends BodyTagSupport 
+        implements TryCatchFinally, ParamParent {
+
+    //*********************************************************************
+    // Public constants
+    
+    /** <p>Valid characters in a scheme.</p>
+     *  <p>RFC 1738 says the following:</p>
+     *  <blockquote>
+     *   Scheme names consist of a sequence of characters. The lower
+     *   case letters "a"--"z", digits, and the characters plus ("+"),
+     *   period ("."), and hyphen ("-") are allowed. For resiliency,
+     *   programs interpreting URLs should treat upper case letters as
+     *   equivalent to lower case in scheme names (e.g., allow "HTTP" as
+     *   well as "http").
+     *  </blockquote>
+     * <p>We treat as absolute any URL that begins with such a scheme name,
+     * followed by a colon.</p>
+     */
+    public static final String VALID_SCHEME_CHARS =
+	"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+.-";
+
+    /** Default character encoding for response. */
+    public static final String DEFAULT_ENCODING = "ISO-8859-1";
+
+    //*********************************************************************
+    // Protected state
+
+    protected String url;                         // 'url' attribute
+    protected String context;			  // 'context' attribute
+    protected String charEncoding;                // 'charEncoding' attrib.
+
+    //*********************************************************************
+    // Private state (implementation details)
+
+    private String var;                 // 'var' attribute
+    private int scope;			// processed 'scope' attribute
+    private String varReader;           // 'varReader' attribute
+    private Reader r;	 		// exposed reader, if relevant
+    private boolean isAbsoluteUrl;	// is our URL absolute?
+    private ParamSupport.ParamManager params;    // parameters
+    private String urlWithParams;	// URL with parameters, if applicable
+
+    //*********************************************************************
+    // Constructor and initialization
+
+    public ImportSupport() {
+	super();
+	init();
+    }
+
+    private void init() {
+	url = var = varReader = context = charEncoding = urlWithParams = null;
+	params = null;
+        scope = PageContext.PAGE_SCOPE;
+    }
+
+
+    //*********************************************************************
+    // Tag logic
+
+    // determines what kind of import and variable exposure to perform 
+    public int doStartTag() throws JspException {
+	// Sanity check
+	if (context != null
+	        && (!context.startsWith("/") || !url.startsWith("/"))) {
+	    throw new JspTagException(
+		Resources.getMessage("IMPORT_BAD_RELATIVE"));
+	}
+
+	// reset parameter-related state
+	urlWithParams = null;
+	params = new ParamSupport.ParamManager();
+
+	// check the URL
+	if (url == null || url.equals(""))
+	    throw new NullAttributeException("import", "url");
+
+	// Record whether our URL is absolute or relative
+	isAbsoluteUrl = isAbsoluteUrl();
+
+	try {
+	    // If we need to expose a Reader, we've got to do it right away
+	    if  (varReader != null) {
+	        r = acquireReader();
+	        pageContext.setAttribute(varReader, r);
+	    }
+	} catch (IOException ex) {
+	    throw new JspTagException(ex.toString(), ex);
+	}
+
+	return EVAL_BODY_INCLUDE;
+    }
+
+    // manages connections as necessary (creating or destroying)
+    public int doEndTag() throws JspException {
+        try {
+	    // If we didn't expose a Reader earlier...
+	    if (varReader == null) {
+	        // ... store it in 'var', if available ...
+	        if (var != null)
+	            pageContext.setAttribute(var, acquireString(), scope);
+                // ... or simply output it, if we have nowhere to expose it
+	        else
+	            pageContext.getOut().print(acquireString());
+	    }
+	    return EVAL_PAGE;
+        } catch (IOException ex) {
+	    throw new JspTagException(ex.toString(), ex);
+        }
+    }
+
+    // simply rethrows its exception
+    public void doCatch(Throwable t) throws Throwable {
+	throw t;
+    }
+
+    // cleans up if appropriate
+    public void doFinally() { 
+        try {
+	    // If we exposed a Reader in doStartTag(), close it.
+	    if (varReader != null) {
+		// 'r' can be null if an exception was thrown...
+	        if (r != null)
+		    r.close();
+		pageContext.removeAttribute(varReader, PageContext.PAGE_SCOPE);
+	    }
+        } catch (IOException ex) {
+	    // ignore it; close() failed, but there's nothing more we can do
+        }
+    }
+
+    // Releases any resources we may have (or inherit)
+    public void release() {
+	init();
+        super.release();
+    }
+
+    //*********************************************************************
+    // Tag attributes known at translation time
+
+    public void setVar(String var) {
+	this.var = var;
+    }
+
+    public void setVarReader(String varReader) {
+	this.varReader = varReader;
+    }
+
+    public void setScope(String scope) {
+	this.scope = Util.getScope(scope);
+    }
+
+
+    //*********************************************************************
+    // Collaboration with subtags
+
+    // inherit Javadoc
+    public void addParameter(String name, String value) {
+	params.addParameter(name, value);
+    }
+
+    //*********************************************************************
+    // Actual URL importation logic
+
+    /*
+     * Overall strategy:  we have two entry points, acquireString() and
+     * acquireReader().  The latter passes data through unbuffered if
+     * possible (but note that it is not always possible -- specifically
+     * for cases where we must use the RequestDispatcher.  The remaining
+     * methods handle the common.core logic of loading either a URL or a local
+     * resource.
+     *
+     * We consider the 'natural' form of absolute URLs to be Readers and
+     * relative URLs to be Strings.  Thus, to avoid doing extra work,
+     * acquireString() and acquireReader() delegate to one another as
+     * appropriate.  (Perhaps I could have spelled things out more clearly,
+     * but I thought this implementation was instructive, not to mention
+     * somewhat cute...)
+     */
+
+    private String acquireString() throws IOException, JspException {
+	if (isAbsoluteUrl) {
+	    // for absolute URLs, delegate to our peer
+	    BufferedReader r = new BufferedReader(acquireReader());
+	    StringBuffer sb = new StringBuffer();
+	    int i;
+
+	    // under JIT, testing seems to show this simple loop is as fast
+	    // as any of the alternatives
+	    while ((i = r.read()) != -1)
+	        sb.append((char)i);
+
+	    return sb.toString();
+	} else { 
+	    // handle relative URLs ourselves
+
+	    // URL is relative, so we must be an HTTP request
+	    if (!(pageContext.getRequest() instanceof HttpServletRequest
+		  && pageContext.getResponse() instanceof HttpServletResponse))
+		throw new JspTagException(
+		    Resources.getMessage("IMPORT_REL_WITHOUT_HTTP"));
+
+	    // retrieve an appropriate ServletContext
+	    ServletContext c = null;
+	    String targetUrl = targetUrl();
+	    if (context != null)
+	        c = pageContext.getServletContext().getContext(context);
+	    else {
+	        c = pageContext.getServletContext();
+
+		// normalize the URL if we have an HttpServletRequest
+		if (!targetUrl.startsWith("/")) {
+		    String sp = ((HttpServletRequest) 
+			pageContext.getRequest()).getServletPath();
+		    targetUrl = sp.substring(0, sp.lastIndexOf('/'))
+			+ '/' + targetUrl;
+		}
+	    }
+
+            if (c == null) {
+                throw new JspTagException(
+                    Resources.getMessage(
+                        "IMPORT_REL_WITHOUT_DISPATCHER", context, targetUrl));
+            }
+
+	    // from this context, get a dispatcher
+	    RequestDispatcher rd =
+                c.getRequestDispatcher(stripSession(targetUrl));
+	    if (rd == null)
+		throw new JspTagException(stripSession(targetUrl));
+
+	    // include the resource, using our custom wrapper
+	    ImportResponseWrapper irw = 
+		new ImportResponseWrapper(
+		    (HttpServletResponse) pageContext.getResponse());
+
+	    // spec mandates specific error handling form include()
+	    try {
+	        rd.include(pageContext.getRequest(), irw);
+	    } catch (IOException ex) {
+		throw new JspException(ex);
+	    } catch (RuntimeException ex) {
+		throw new JspException(ex);
+	    } catch (ServletException ex) {
+		Throwable rc = ex.getRootCause();
+		if (rc == null)
+		    throw new JspException(ex);
+		else
+		    throw new JspException(rc);
+	    }
+
+	    // disallow inappropriate response codes per JSTL spec
+	    if (irw.getStatus() < 200 || irw.getStatus() > 299) {
+		throw new JspTagException(irw.getStatus() + " " +
+		    stripSession(targetUrl));
+	    }
+
+	    // recover the response String from our wrapper
+	    return irw.getString();
+	}
+    }
+
+    private Reader acquireReader() throws IOException, JspException {
+	if (!isAbsoluteUrl) {
+	    // for relative URLs, delegate to our peer
+	    return new StringReader(acquireString());
+	} else {
+            // absolute URL
+            String target = targetUrl();
+	    try {
+	        // handle absolute URLs ourselves, using java.net.URL
+	        URL u = new URL(target);
+                URLConnection uc = u.openConnection();
+                InputStream i = uc.getInputStream();
+
+	        // okay, we've got a stream; encode it appropriately
+	        Reader r = null;
+                String charSet; 
+	        if (charEncoding != null && !charEncoding.equals("")) {
+                    charSet = charEncoding;
+                } else {
+                    // charSet extracted according to RFC 2045, section 5.1
+		    String contentType = uc.getContentType();
+		    if (contentType != null) {
+                        charSet = Util.getContentTypeAttribute(contentType, "charset");
+                        if (charSet == null) charSet = DEFAULT_ENCODING;
+                    } else {
+                        charSet = DEFAULT_ENCODING;
+                    }
+                }
+                try {
+                    r = new InputStreamReader(i, charSet);
+                } catch (Exception ex) {
+                    r = new InputStreamReader(i, DEFAULT_ENCODING);
+                }
+
+		// check response code for HTTP URLs before returning, per spec,
+		// before returning
+		if (uc instanceof HttpURLConnection) {
+		    int status = ((HttpURLConnection) uc).getResponseCode();
+		    if (status < 200 || status > 299)
+			throw new JspTagException(status + " " + target);
+		}
+
+	        return r;
+	    } catch (IOException ex) {
+		throw new JspException(
+                    Resources.getMessage("IMPORT_ABS_ERROR", target, ex), ex);
+	    } catch (RuntimeException ex) {  // because the spec makes us
+		throw new JspException(
+                    Resources.getMessage("IMPORT_ABS_ERROR", target, ex), ex);
+	    }
+	}
+    }
+
+    /** Wraps responses to allow us to retrieve results as Strings. */
+    private class ImportResponseWrapper extends HttpServletResponseWrapper {
+
+	//************************************************************
+	// Overview
+
+	/*
+	 * We provide either a Writer or an OutputStream as requested.
+	 * We actually have a true Writer and an OutputStream backing
+	 * both, since we don't want to use a character encoding both
+	 * ways (Writer -> OutputStream -> Writer).  So we use no
+	 * encoding at all (as none is relevant) when the target resource
+	 * uses a Writer.  And we decode the OutputStream's bytes
+	 * using OUR tag's 'charEncoding' attribute, or ISO-8859-1
+	 * as the default.  We thus ignore setLocale() and setContentType()
+	 * in this wrapper.
+	 *
+	 * In other words, the target's asserted encoding is used
+	 * to convert from a Writer to an OutputStream, which is typically
+	 * the medium through with the target will communicate its
+	 * ultimate response.  Since we short-circuit that mechanism
+	 * and read the target's characters directly if they're offered
+	 * as such, we simply ignore the target's encoding assertion.
+	 */
+
+	//************************************************************
+	// Data
+
+	/** The Writer we convey. */
+	private StringWriter sw = new StringWriter();
+
+	/** A buffer, alternatively, to accumulate bytes. */
+	private ByteArrayOutputStream bos = new ByteArrayOutputStream();
+
+	/** A ServletOutputStream we convey, tied to this Writer. */
+	private ServletOutputStream sos = new ServletOutputStream() {
+	    public void write(int b) throws IOException {
+		bos.write(b);
+	    }
+	};
+
+	/** 'True' if getWriter() was called; false otherwise. */
+	private boolean isWriterUsed;
+
+	/** 'True if getOutputStream() was called; false otherwise. */
+	private boolean isStreamUsed;
+
+	/** The HTTP status set by the target. */
+	private int status = 200;
+	
+	//************************************************************
+	// Constructor and methods
+
+	/** Constructs a new ImportResponseWrapper. */
+	public ImportResponseWrapper(HttpServletResponse response) {
+	    super(response);
+	}
+	
+	/** Returns a Writer designed to buffer the output. */
+	public PrintWriter getWriter() {
+	    if (isStreamUsed)
+		throw new IllegalStateException(
+		    Resources.getMessage("IMPORT_ILLEGAL_STREAM"));
+	    isWriterUsed = true;
+	    return new PrintWriter(sw);
+	}
+	
+	/** Returns a ServletOutputStream designed to buffer the output. */
+	public ServletOutputStream getOutputStream() {
+	    if (isWriterUsed)
+		throw new IllegalStateException(
+		    Resources.getMessage("IMPORT_ILLEGAL_WRITER"));
+	    isStreamUsed = true;
+	    return sos;
+	}
+
+	/** Has no effect. */
+	public void setContentType(String x) {
+	    // ignore
+	}
+
+	/** Has no effect. */
+	public void setLocale(Locale x) {
+	    // ignore
+	}
+
+	public void setStatus(int status) {
+	    this.status = status;
+	}
+
+	public int getStatus() {
+	    return status;
+	}
+
+	/** 
+	 * Retrieves the buffered output, using the containing tag's 
+	 * 'charEncoding' attribute, or the tag's default encoding,
+	 * <b>if necessary</b>.
+         */
+	// not simply toString() because we need to throw
+	// UnsupportedEncodingException
+	public String getString() throws UnsupportedEncodingException {
+	    if (isWriterUsed)
+		return sw.toString();
+	    else if (isStreamUsed) {
+		if (charEncoding != null && !charEncoding.equals(""))
+		    return bos.toString(charEncoding);
+		else
+		    return bos.toString(DEFAULT_ENCODING);
+	    } else
+		return "";		// target didn't write anything
+	}
+    }
+
+    //*********************************************************************
+    // Some private utility methods
+
+    /** Returns our URL (potentially with parameters) */
+    private String targetUrl() {
+	if (urlWithParams == null)
+	    urlWithParams = params.aggregateParams(url);
+	return urlWithParams;
+    }
+
+    /**
+     * Returns <tt>true</tt> if our current URL is absolute,
+     * <tt>false</tt> otherwise.
+     */
+    private boolean isAbsoluteUrl() throws JspTagException {
+        return isAbsoluteUrl(url);
+    }
+
+
+    //*********************************************************************
+    // Public utility methods
+
+    /**
+     * Returns <tt>true</tt> if our current URL is absolute,
+     * <tt>false</tt> otherwise.
+     */
+    public static boolean isAbsoluteUrl(String url) {
+	// a null URL is not absolute, by our definition
+	if (url == null)
+	    return false;
+
+	// do a fast, simple check first
+	int colonPos;
+	if ((colonPos = url.indexOf(":")) == -1)
+	    return false;
+
+	// if we DO have a colon, make sure that every character
+	// leading up to it is a valid scheme character
+	for (int i = 0; i < colonPos; i++)
+	    if (VALID_SCHEME_CHARS.indexOf(url.charAt(i)) == -1)
+		return false;
+
+	// if so, we've got an absolute url
+	return true;
+    }
+
+    /**
+     * Strips a servlet session ID from <tt>url</tt>.  The session ID
+     * is encoded as a URL "path parameter" beginning with "jsessionid=".
+     * We thus remove anything we find between ";jsessionid=" (inclusive)
+     * and either EOS or a subsequent ';' (exclusive).
+     */
+    public static String stripSession(String url) {
+	StringBuffer u = new StringBuffer(url);
+        int sessionStart;
+        while ((sessionStart = u.toString().indexOf(";jsessionid=")) != -1) {
+            int sessionEnd = u.toString().indexOf(";", sessionStart + 1);
+            if (sessionEnd == -1)
+		sessionEnd = u.toString().indexOf("?", sessionStart + 1);
+	    if (sessionEnd == -1) 				// still
+                sessionEnd = u.length();
+            u.delete(sessionStart, sessionEnd);
+        }
+        return u.toString();
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/common/core/NullAttributeException.java b/standard/src/org/apache/taglibs/standard/tag/common/core/NullAttributeException.java
new file mode 100644
index 0000000..fca620d
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/common/core/NullAttributeException.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.common.core;
+
+import javax.servlet.jsp.JspTagException;
+
+import org.apache.taglibs.standard.resources.Resources;
+
+/**
+ * <p>NullAttributeException is a JspTagException that will be thrown
+ * by the JSTL RI handlers when a tag attribute illegally evaluates
+ * to 'null'.</p>
+ *
+ * @author Shawn Bayern
+ */
+
+public class NullAttributeException extends JspTagException {
+
+    /**
+     * Constructs a NullAttributeException with appropriate information.
+     *
+     * @param tag The name of the tag in which the error occurred.
+     * @param att The attribute value for which the error occurred.
+     */
+    public NullAttributeException(String tag, String att) {
+	super(Resources.getMessage("TAG_NULL_ATTRIBUTE", att, tag));
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/common/core/OtherwiseTag.java b/standard/src/org/apache/taglibs/standard/tag/common/core/OtherwiseTag.java
new file mode 100644
index 0000000..c643470
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/common/core/OtherwiseTag.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.common.core;
+
+
+/**
+ * <p>Tag handler for <otherwise> in JSTL.</p>
+ *
+ * @author Shawn Bayern
+ */
+
+public class OtherwiseTag extends WhenTagSupport {
+
+    /*
+     * <otherwise> is just a <when> that always tries to evaluate its body
+     * if it has permission from its parent tag.
+     */
+
+    // Don't let the condition stop us... :-)
+    protected boolean condition() {
+        return true;
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/common/core/OutSupport.java b/standard/src/org/apache/taglibs/standard/tag/common/core/OutSupport.java
new file mode 100644
index 0000000..cae2409
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/common/core/OutSupport.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.common.core;
+
+import java.io.IOException;
+import java.io.Reader;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.JspWriter;
+import javax.servlet.jsp.PageContext;
+import javax.servlet.jsp.tagext.BodyTagSupport;
+
+/**
+ * <p>Support for handlers of the <out> tag, which simply evalutes and
+ * prints the result of the expression it's passed.  If the result is
+ * null, we print the value of the 'default' attribute's expression or
+ * our body (which two are mutually exclusive, although this constraint
+ * is enforced outside this handler, in our TagLibraryValidator).</p>
+ *
+ * @author Shawn Bayern
+ */
+public class OutSupport extends BodyTagSupport {
+
+    /*
+     * (One almost wishes XML and JSP could support "anonymous tags,"
+     * given the amount of trouble we had naming this one!)  :-)  - sb
+     */
+
+    //*********************************************************************
+    // Internal state
+
+    protected Object value;                     // tag attribute
+    protected String def;			// tag attribute
+    protected boolean escapeXml;		// tag attribute
+    private boolean needBody;			// non-space body needed?
+
+    //*********************************************************************
+    // Construction and initialization
+
+    /**
+     * Constructs a new handler.  As with TagSupport, subclasses should
+     * not provide other constructors and are expected to call the
+     * superclass constructor.
+     */
+    public OutSupport() {
+        super();
+        init();
+    }
+
+    // resets local state
+    private void init() {
+        value = def = null;
+        escapeXml = true;
+	needBody = false;
+    }
+
+    // Releases any resources we may have (or inherit)
+    public void release() {
+        super.release();
+        init();
+    }
+
+
+    //*********************************************************************
+    // Tag logic
+
+    // evaluates 'value' and determines if the body should be evaluted
+    public int doStartTag() throws JspException {
+
+      needBody = false;			// reset state related to 'default'
+      this.bodyContent = null;  // clean-up body (just in case container is pooling tag handlers)
+      
+      try {
+	// print value if available; otherwise, try 'default'
+	if (value != null) {
+            out(pageContext, escapeXml, value);
+	    return SKIP_BODY;
+	} else {
+	    // if we don't have a 'default' attribute, just go to the body
+	    if (def == null) {
+		needBody = true;
+		return EVAL_BODY_BUFFERED;
+	    }
+
+	    // if we do have 'default', print it
+	    if (def != null) {
+		// good 'default'
+                out(pageContext, escapeXml, def);
+	    }
+	    return SKIP_BODY;
+	}
+      } catch (IOException ex) {
+	throw new JspException(ex.toString(), ex);
+      }
+    }
+
+    // prints the body if necessary; reports errors
+    public int doEndTag() throws JspException {
+      try {
+	if (!needBody)
+	    return EVAL_PAGE;		// nothing more to do
+
+	// trim and print out the body
+	if (bodyContent != null && bodyContent.getString() != null)
+            out(pageContext, escapeXml, bodyContent.getString().trim());
+	return EVAL_PAGE;
+      } catch (IOException ex) {
+	throw new JspException(ex.toString(), ex);
+      }
+    }
+
+
+    //*********************************************************************
+    // Public utility methods
+
+    /**
+     * Outputs <tt>text</tt> to <tt>pageContext</tt>'s current JspWriter.
+     * If <tt>escapeXml</tt> is true, performs the following substring
+     * replacements (to facilitate output to XML/HTML pages):
+     *
+     *    & -> &
+     *    < -> <
+     *    > -> >
+     *    " -> "
+     *    ' -> '
+     *
+     * See also Util.escapeXml().
+     */
+    public static void out(PageContext pageContext,
+                           boolean escapeXml,
+                           Object obj) throws IOException {
+        JspWriter w = pageContext.getOut();
+	if (!escapeXml) {
+            // write chars as is
+            if (obj instanceof Reader) {
+                Reader reader = (Reader)obj;
+                char[] buf = new char[4096];
+                int count;
+                while ((count=reader.read(buf, 0, 4096)) != -1) {
+                    w.write(buf, 0, count);
+                }
+            } else {
+                w.write(obj.toString());
+            }
+        } else {
+            // escape XML chars
+            if (obj instanceof Reader) {
+                Reader reader = (Reader)obj;
+                char[] buf = new char[4096];
+                int count;
+                while ((count = reader.read(buf, 0, 4096)) != -1) {
+                    writeEscapedXml(buf, count, w);
+                }
+            } else {
+                String text = obj.toString();
+                writeEscapedXml(text.toCharArray(), text.length(), w);
+            }
+        }
+    }
+
+   /**
+     *
+     *  Optimized to create no extra objects and write directly
+     *  to the JspWriter using blocks of escaped and unescaped characters
+     *
+     */
+    private static void writeEscapedXml(char[] buffer, int length, JspWriter w) throws IOException{
+        int start = 0;
+
+        for (int i = 0; i < length; i++) {
+            char c = buffer[i];
+            if (c <= Util.HIGHEST_SPECIAL) {
+                char[] escaped = Util.specialCharactersRepresentation[c];
+                if (escaped != null) {
+                    // add unescaped portion
+                    if (start < i) {
+                        w.write(buffer,start,i-start);
+                    }
+                    // add escaped xml
+                    w.write(escaped);
+                    start = i + 1;
+                }
+            }
+        }
+        // add rest of unescaped portion
+        if (start < length) {
+            w.write(buffer,start,length-start);
+        }
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/common/core/ParamParent.java b/standard/src/org/apache/taglibs/standard/tag/common/core/ParamParent.java
new file mode 100644
index 0000000..2bb4840
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/common/core/ParamParent.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.common.core;
+
+/**
+ * <p>Interface for tag handlers implementing valid parent tags for
+ * <c:param>.</p>
+ *
+ * @author Shawn Bayern
+ */
+
+public interface ParamParent {
+
+    /**
+     * Adds a parameter to this tag's URL.  The intent is that the
+     * <param> subtag will call this to register URL parameters.
+     * Assumes that 'name' and 'value' are appropriately encoded and do
+     * not contain any meaningful metacharacters; in order words, escaping
+     * is the responsibility of the caller.
+     *
+     * @see ParamSupport
+     */
+    void addParameter(String name, String value);
+
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/common/core/ParamSupport.java b/standard/src/org/apache/taglibs/standard/tag/common/core/ParamSupport.java
new file mode 100644
index 0000000..42cbba9
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/common/core/ParamSupport.java
@@ -0,0 +1,178 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.common.core;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.JspTagException;
+import javax.servlet.jsp.tagext.BodyTagSupport;
+import javax.servlet.jsp.tagext.Tag;
+
+import org.apache.taglibs.standard.resources.Resources;
+
+/**
+ * <p>Support for tag handlers for <param>, the URL parameter
+ * subtag for <import> in JSTL 1.0.</p>
+ *
+ * @see ParamParent, ImportSupport, URLEncodeSupport
+ * @author Shawn Bayern
+ */
+
+public abstract class ParamSupport extends BodyTagSupport {
+
+    //*********************************************************************
+    // Protected state
+
+    protected String name;                       // 'name' attribute
+    protected String value;                      // 'value' attribute
+
+    /**
+     * There used to be an 'encode' attribute; I've left this as a
+     * vestige in case custom subclasses want to use our functionality
+     * but NOT encode parameters.
+     */
+    protected boolean encode = true;
+
+    //*********************************************************************
+    // Constructor and initialization
+
+    public ParamSupport() {
+	super();
+	init();
+    }
+
+    private void init() {
+	name = value = null;
+    }
+
+    //*********************************************************************
+    // Tag logic
+
+    // simply send our name and value to our appropriate ancestor
+    public int doEndTag() throws JspException {
+	Tag t = findAncestorWithClass(this, ParamParent.class);
+	if (t == null)
+	    throw new JspTagException(
+		Resources.getMessage("PARAM_OUTSIDE_PARENT"));
+
+	// take no action for null or empty names
+	if (name == null || name.equals(""))
+	    return EVAL_PAGE;
+
+	// send the parameter to the appropriate ancestor
+	ParamParent parent = (ParamParent) t;
+	String value = this.value;
+	if (value == null) {
+	    if (bodyContent == null || bodyContent.getString() == null)
+		value = "";
+	    else
+		value = bodyContent.getString().trim();
+	}
+        if (encode) {
+            // FIXME: revert to java.net.URLEncoder.encode(s, enc) once
+            // we have a dependency on J2SE 1.4+.
+            String enc = pageContext.getResponse().getCharacterEncoding();
+            parent.addParameter(
+            Util.URLEncode(name, enc), Util.URLEncode(value, enc));
+        } else {
+            parent.addParameter(name, value);
+        }
+	return EVAL_PAGE;
+    }
+
+    // Releases any resources we may have (or inherit)
+    public void release() {
+	init();
+    }
+
+    //*********************************************************************
+    // Support for parameter management
+
+    /** 
+     * Provides support for aggregating query parameters in URLs.
+     * Specifically, accepts a series of parameters, ensuring that
+     *  - newer parameters will precede older ones in the output URL
+     *  - all supplied parameters precede those in the input URL
+     */
+    public static class ParamManager {
+
+        //*********************************
+        // Private state
+
+	private List names = new LinkedList();
+        private List values = new LinkedList();
+	private boolean done = false;
+        
+	//*********************************
+        // Public interface
+
+	/** Adds a new parameter to the list. */
+        public void addParameter(String name, String value) {
+	    if (done)
+		throw new IllegalStateException();
+	    if (name != null) {
+	        names.add(name);
+	        if (value != null)
+		    values.add(value);
+	        else
+		    values.add("");
+	    }
+	}
+
+	/**
+         * Produces a new URL with the stored parameters, in the appropriate
+         * order.
+         */
+	public String aggregateParams(String url) {
+	    /* 
+             * Since for efficiency we're destructive to the param lists,
+             * we don't want to run multiple times.
+             */
+	    if (done)
+		throw new IllegalStateException();
+	    done = true;
+
+	    //// reverse the order of our two lists
+	    // Collections.reverse(this.names);
+	    // Collections.reverse(this.values);
+
+	    // build a string from the parameter list 
+	    StringBuffer newParams = new StringBuffer();
+	    for (int i = 0; i < names.size(); i++) {
+		newParams.append(names.get(i) + "=" + values.get(i));
+		if (i < (names.size() - 1))
+		    newParams.append("&");
+	    }
+
+	    // insert these parameters into the URL as appropriate
+	    if (newParams.length() > 0) {
+	        int questionMark = url.indexOf('?');
+	        if (questionMark == -1) {
+		    return (url + "?" + newParams);
+	        } else {
+		    StringBuffer workingUrl = new StringBuffer(url);
+		    workingUrl.insert(questionMark + 1, (newParams + "&"));
+		    return workingUrl.toString();
+	        }
+	    } else {
+		return url;
+	    }
+	}
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/common/core/RedirectSupport.java b/standard/src/org/apache/taglibs/standard/tag/common/core/RedirectSupport.java
new file mode 100644
index 0000000..a09945c
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/common/core/RedirectSupport.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.common.core;
+
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.JspTagException;
+import javax.servlet.jsp.PageContext;
+import javax.servlet.jsp.tagext.BodyTagSupport;
+
+/**
+ * <p>Support for tag handlers for <redirect>, JSTL 1.0's tag
+ * for redirecting to a new URL (with optional query parameters).</p>
+ *
+ * @author Shawn Bayern
+ */
+
+public abstract class RedirectSupport extends BodyTagSupport
+    implements ParamParent {
+
+    //*********************************************************************
+    // Protected state
+
+    protected String url;                        // 'url' attribute
+    protected String context;                    // 'context' attribute
+
+    //*********************************************************************
+    // Private state
+
+    private String var;                          // 'var' attribute
+    private int scope;				 // processed 'scope' attr
+    private ParamSupport.ParamManager params;	 // added parameters
+
+    //*********************************************************************
+    // Constructor and initialization
+
+    public RedirectSupport() {
+	super();
+	init();
+    }
+
+    private void init() {
+	url = var = null;
+	params = null;
+	scope = PageContext.PAGE_SCOPE;
+    }
+
+
+   //*********************************************************************
+    // Tag attributes known at translation time
+
+    public void setVar(String var) {
+        this.var = var;
+    }
+
+    public void setScope(String scope) {
+	this.scope = Util.getScope(scope);
+    }
+
+
+    //*********************************************************************
+    // Collaboration with subtags
+
+    // inherit Javadoc
+    public void addParameter(String name, String value) {
+	params.addParameter(name, value);
+    }
+
+
+    //*********************************************************************
+    // Tag logic
+
+    // resets any parameters that might be sent
+    public int doStartTag() throws JspException {
+	params = new ParamSupport.ParamManager();
+	return EVAL_BODY_BUFFERED;
+    }
+
+
+    // gets the right value, encodes it, and prints or stores it
+    public int doEndTag() throws JspException {
+	String result;				// the eventual result
+
+	// add (already encoded) parameters
+        String baseUrl = UrlSupport.resolveUrl(url, context, pageContext);
+        result = params.aggregateParams(baseUrl);
+
+        // if the URL is relative, rewrite it with 'redirect' encoding rules
+        HttpServletResponse response =
+            ((HttpServletResponse) pageContext.getResponse());
+        if (!ImportSupport.isAbsoluteUrl(result))
+            result = response.encodeRedirectURL(result);
+
+	// redirect!
+	try {
+	    response.sendRedirect(result);
+	} catch (java.io.IOException ex) {
+	    throw new JspTagException(ex.toString(), ex);
+	}
+
+	return SKIP_PAGE;
+    }
+
+    // Releases any resources we may have (or inherit)
+    public void release() {
+	init();
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/common/core/RemoveTag.java b/standard/src/org/apache/taglibs/standard/tag/common/core/RemoveTag.java
new file mode 100644
index 0000000..f633934
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/common/core/RemoveTag.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.common.core;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.PageContext;
+import javax.servlet.jsp.tagext.TagSupport;
+
+/**
+ * <p>A handler for the <remove> tag, which removes the variable
+ * identified by 'var' (and 'scope', if present).
+ *
+ * @author Shawn Bayern
+ */
+public class RemoveTag extends TagSupport {
+
+    //*********************************************************************
+    // Constants
+
+    /* We support these 'scopes'. */
+
+    private final String APPLICATION = "application";
+    private final String SESSION = "session";
+    private final String REQUEST = "request";
+    private final String PAGE = "page";
+
+    //*********************************************************************
+    // Internal state
+
+    private int scope;					// tag attribute
+    private boolean scopeSpecified;			// ... by tag attribute
+    private String var;					// tag attribute
+
+
+    //*********************************************************************
+    // Construction and initialization
+
+    /**
+     * Constructs a new handler.  As with TagSupport, subclasses should
+     * not provide other constructors and are expected to call the
+     * superclass constructor.
+     */
+    public RemoveTag() {
+        super();
+        init();
+    }
+
+    // resets local state
+    private void init() {
+        var = null;
+        scope = PageContext.PAGE_SCOPE;
+        scopeSpecified = false;
+    }
+
+    // Releases any resources we may have (or inherit)
+    public void release() {
+        super.release();
+        init();
+    }
+
+
+    //*********************************************************************
+    // Tag logic
+
+    // removes the variable (from a specific scope, if specified)
+    public int doEndTag() throws JspException {
+        if (!scopeSpecified)
+            pageContext.removeAttribute(var);
+        else
+            pageContext.removeAttribute(var, scope);
+	return EVAL_PAGE;
+    }
+
+
+    //*********************************************************************
+    // Accessor methods
+
+    // for tag attribute
+    public void setVar(String var) {
+	this.var = var;
+    }
+
+    // for tag attribute
+    public void setScope(String scope) {
+        this.scope = Util.getScope(scope);
+	scopeSpecified = true;
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/common/core/SetSupport.java b/standard/src/org/apache/taglibs/standard/tag/common/core/SetSupport.java
new file mode 100644
index 0000000..d10e0fa
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/common/core/SetSupport.java
@@ -0,0 +1,210 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.common.core;
+
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Map;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.JspTagException;
+import javax.servlet.jsp.PageContext;
+import javax.servlet.jsp.el.ELException;
+import javax.servlet.jsp.el.ExpressionEvaluator;
+import javax.servlet.jsp.el.VariableResolver;
+import javax.servlet.jsp.tagext.BodyTagSupport;
+
+import org.apache.taglibs.standard.resources.Resources;
+
+/**
+ * <p>Support for handlers of the <set> tag.</p>
+ *
+ * @author Shawn Bayern
+ */
+public class SetSupport extends BodyTagSupport {
+
+    //*********************************************************************
+    // Internal state
+
+    protected Object value;                             // tag attribute
+    protected boolean valueSpecified;			// status
+    protected Object target;                            // tag attribute
+    protected String property;                          // tag attribute
+    private String var;					// tag attribute
+    private int scope;					// tag attribute
+    private boolean scopeSpecified;			// status
+
+    //*********************************************************************
+    // Construction and initialization
+
+    /**
+     * Constructs a new handler.  As with TagSupport, subclasses should
+     * not provide other constructors and are expected to call the
+     * superclass constructor.
+     */
+    public SetSupport() {
+        super();
+        init();
+    }
+
+    // resets local state
+    private void init() {
+        value = var = null;
+	scopeSpecified = valueSpecified = false;
+	scope = PageContext.PAGE_SCOPE;
+    }
+
+    // Releases any resources we may have (or inherit)
+    public void release() {
+        super.release();
+        init();
+    }
+
+
+    //*********************************************************************
+    // Tag logic
+
+    public int doEndTag() throws JspException {
+
+        Object result;		// what we'll store in scope:var
+
+        // determine the value by...
+        if (value != null) {
+	    // ... reading our attribute
+	    result = value;
+  	} else if (valueSpecified) {
+	    // ... accepting an explicit null
+	    result = null;
+	} else {
+	    // ... retrieving and trimming our body
+	    if (bodyContent == null || bodyContent.getString() == null)
+		result = "";
+	    else
+	        result = bodyContent.getString().trim();
+	}
+
+	// decide what to do with the result
+	if (var != null) {
+
+	    /*
+             * Store the result, letting an IllegalArgumentException
+             * propagate back if the scope is invalid (e.g., if an attempt
+             * is made to store something in the session without any
+	     * HttpSession existing).
+             */
+	    if (result != null) {
+	        pageContext.setAttribute(var, result, scope);
+	    } else {
+		if (scopeSpecified)
+		    pageContext.removeAttribute(var, scope);
+		else
+		    pageContext.removeAttribute(var);
+	    }
+
+	} else if (target != null) {
+
+	    // save the result to target.property
+	    if (target instanceof Map) {
+		// ... treating it as a Map entry
+		if (result == null)
+		    ((Map) target).remove(property);
+		else
+		    ((Map) target).put(property, result);
+	    } else {
+		// ... treating it as a bean property
+		try {
+                    PropertyDescriptor pd[] =
+                        Introspector.getBeanInfo(target.getClass())
+			    .getPropertyDescriptors();
+		    boolean succeeded = false;
+                    for (int i = 0; i < pd.length; i++) {
+                        if (pd[i].getName().equals(property)) {
+			    Method m = pd[i].getWriteMethod();
+                            if (m == null) {
+                                throw new JspException(
+                                    Resources.getMessage("SET_NO_SETTER_METHOD",
+				        property));
+                            }
+			    if (result != null) {  
+                                try {
+			        m.invoke(target,
+			             new Object[] { 
+                                         convertToExpectedType(result, m.getParameterTypes()[0])});
+                                } catch (javax.servlet.jsp.el.ELException ex) {
+                                    throw new JspTagException(ex);
+                                }
+			    } else {
+				m.invoke(target, new Object[] { null });
+			    }
+			    succeeded = true;
+			}
+		    }
+		    if (!succeeded) {
+			throw new JspTagException(
+			    Resources.getMessage("SET_INVALID_PROPERTY",
+				property));
+		    }
+		} catch (IllegalAccessException ex) {
+		    throw new JspException(ex);
+		} catch (IntrospectionException ex) {
+		    throw new JspException(ex);
+		} catch (InvocationTargetException ex) {
+		    throw new JspException(ex);
+		}
+	    }
+	} else {
+	    // should't ever occur because of validation in TLV and setters
+	    throw new JspTagException();
+	}
+
+	return EVAL_PAGE;
+    }
+    
+    /**
+     * Convert an object to an expected type according to the conversion
+     * rules of the Expression Language.
+     */
+    private Object convertToExpectedType( final Object value,
+    Class expectedType )
+    throws javax.servlet.jsp.el.ELException {
+        ExpressionEvaluator evaluator = pageContext.getExpressionEvaluator();
+        return evaluator.evaluate( "${result}", expectedType,
+        new VariableResolver() {
+            public Object resolveVariable( String pName )
+            throws ELException {
+                return value;
+            }
+        }, null );
+    }
+
+    //*********************************************************************
+    // Accessor methods
+
+    // for tag attribute
+    public void setVar(String var) {
+	this.var = var;
+    }
+
+    // for tag attribute
+    public void setScope(String scope) {
+        this.scope = Util.getScope(scope);
+	this.scopeSpecified = true;
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/common/core/UrlSupport.java b/standard/src/org/apache/taglibs/standard/tag/common/core/UrlSupport.java
new file mode 100644
index 0000000..e04d544
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/common/core/UrlSupport.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.common.core;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.JspTagException;
+import javax.servlet.jsp.PageContext;
+import javax.servlet.jsp.tagext.BodyTagSupport;
+
+import org.apache.taglibs.standard.resources.Resources;
+
+/**
+ * <p>Support for tag handlers for <url>, the URL creation
+ * and rewriting tag in JSTL 1.0.</p>
+ *
+ * @author Shawn Bayern
+ */
+
+public abstract class UrlSupport extends BodyTagSupport
+    implements ParamParent {
+
+    //*********************************************************************
+    // Protected state
+
+    protected String value;                      // 'value' attribute
+    protected String context;			 // 'context' attribute
+
+    //*********************************************************************
+    // Private state
+
+    private String var;                          // 'var' attribute
+    private int scope;				 // processed 'scope' attr
+    private ParamSupport.ParamManager params;	 // added parameters
+
+    //*********************************************************************
+    // Constructor and initialization
+
+    public UrlSupport() {
+	super();
+	init();
+    }
+
+    private void init() {
+	value = var = null;
+	params = null;
+	context = null;
+	scope = PageContext.PAGE_SCOPE;
+    }
+
+
+   //*********************************************************************
+    // Tag attributes known at translation time
+
+    public void setVar(String var) {
+        this.var = var;
+    }
+
+    public void setScope(String scope) {
+	this.scope = Util.getScope(scope);
+    }
+
+
+    //*********************************************************************
+    // Collaboration with subtags
+
+    // inherit Javadoc
+    public void addParameter(String name, String value) {
+	params.addParameter(name, value);
+    }
+
+
+    //*********************************************************************
+    // Tag logic
+
+    // resets any parameters that might be sent
+    public int doStartTag() throws JspException {
+	params = new ParamSupport.ParamManager();
+	return EVAL_BODY_BUFFERED;
+    }
+
+
+    // gets the right value, encodes it, and prints or stores it
+    public int doEndTag() throws JspException {
+	String result;				// the eventual result
+
+	// add (already encoded) parameters
+	String baseUrl = resolveUrl(value, context, pageContext);
+	result = params.aggregateParams(baseUrl);
+
+	// if the URL is relative, rewrite it
+	if (!ImportSupport.isAbsoluteUrl(result)) {
+	    HttpServletResponse response =
+                ((HttpServletResponse) pageContext.getResponse());
+            result = response.encodeURL(result);
+	}
+
+	// store or print the output
+	if (var != null)
+	    pageContext.setAttribute(var, result, scope);
+	else {
+	    try {
+	        pageContext.getOut().print(result);
+	    } catch (java.io.IOException ex) {
+		throw new JspTagException(ex.toString(), ex);
+	    }
+	}
+
+	return EVAL_PAGE;
+    }
+
+    // Releases any resources we may have (or inherit)
+    public void release() {
+	init();
+    }
+
+    //*********************************************************************
+    // Utility methods
+
+    public static String resolveUrl(
+            String url, String context, PageContext pageContext)
+	    throws JspException {
+	// don't touch absolute URLs
+	if (ImportSupport.isAbsoluteUrl(url))
+	    return url;
+
+	// normalize relative URLs against a context root
+	HttpServletRequest request =
+	    (HttpServletRequest) pageContext.getRequest();
+	if (context == null) {
+	    if (url.startsWith("/"))
+		return (request.getContextPath() + url);
+	    else
+		return url;
+	} else {
+            if (!context.startsWith("/") || !url.startsWith("/")) {
+                throw new JspTagException(
+                    Resources.getMessage("IMPORT_BAD_RELATIVE"));
+            }
+            if (context.equals("/")) {
+                // Don't produce string starting with '//', many
+                // browsers interpret this as host name, not as
+                // path on same host.
+                return url;
+            } else {
+                return (context + url);
+            }
+        }
+    }
+
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/common/core/Util.java b/standard/src/org/apache/taglibs/standard/tag/common/core/Util.java
new file mode 100644
index 0000000..8238bf4
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/common/core/Util.java
@@ -0,0 +1,293 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.common.core;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.text.DateFormat;
+import java.util.Enumeration;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.PageContext;
+
+import org.apache.taglibs.standard.resources.Resources;
+
+/**
+ * <p>Utilities in support of tag-handler classes.</p>
+ *
+ * @author Jan Luehe
+ */
+public class Util {
+
+    private static final String REQUEST = "request";   
+    private static final String SESSION = "session";   
+    private static final String APPLICATION = "application"; 
+    private static final String DEFAULT = "default";
+    private static final String SHORT = "short";
+    private static final String MEDIUM = "medium";
+    private static final String LONG = "long";
+    private static final String FULL = "full";
+
+    public static final int HIGHEST_SPECIAL = '>';
+    public static char[][] specialCharactersRepresentation = new char[HIGHEST_SPECIAL + 1][];
+    static {
+        specialCharactersRepresentation['&'] = "&".toCharArray();
+        specialCharactersRepresentation['<'] = "<".toCharArray();
+        specialCharactersRepresentation['>'] = ">".toCharArray();
+        specialCharactersRepresentation['"'] = """.toCharArray();
+        specialCharactersRepresentation['\''] = "'".toCharArray();
+    }
+
+    /*
+     * Converts the given string description of a scope to the corresponding
+     * PageContext constant.
+     *
+     * The validity of the given scope has already been checked by the
+     * appropriate TLV.
+     *
+     * @param scope String description of scope
+     *
+     * @return PageContext constant corresponding to given scope description
+     */
+    public static int getScope(String scope) {
+	int ret = PageContext.PAGE_SCOPE; // default
+
+	if (REQUEST.equalsIgnoreCase(scope))
+	    ret = PageContext.REQUEST_SCOPE;
+	else if (SESSION.equalsIgnoreCase(scope))
+	    ret = PageContext.SESSION_SCOPE;
+	else if (APPLICATION.equalsIgnoreCase(scope))
+	    ret = PageContext.APPLICATION_SCOPE;
+
+	return ret;
+    }
+
+    /*
+     * Converts the given string description of a formatting style for
+     * dates and times to the corresponding java.util.DateFormat constant.
+     *
+     * @param style String description of formatting style for dates and times
+     * @param errCode Error code to throw if given style is invalid
+     *
+     * @return java.util.DateFormat constant corresponding to given style
+     *
+     * @throws JspException if the given style is invalid
+     */
+    public static int getStyle(String style, String errCode)
+	                throws JspException {
+	int ret = DateFormat.DEFAULT;
+
+	if (style != null) {
+	    if (DEFAULT.equalsIgnoreCase(style)) {
+		ret = DateFormat.DEFAULT;
+	    } else if (SHORT.equalsIgnoreCase(style)) {
+		ret = DateFormat.SHORT;
+	    } else if (MEDIUM.equalsIgnoreCase(style)) {
+		ret = DateFormat.MEDIUM;
+	    } else if (LONG.equalsIgnoreCase(style)) {
+		ret = DateFormat.LONG;
+	    } else if (FULL.equalsIgnoreCase(style)) {
+		ret = DateFormat.FULL;
+	    } else {
+		throw new JspException(Resources.getMessage(errCode, style));
+	    }
+	}
+
+	return ret;
+    }
+    
+
+
+    /**
+     * Performs the following substring replacements
+     * (to facilitate output to XML/HTML pages):
+     *
+     *    & -> &
+     *    < -> <
+     *    > -> >
+     *    " -> "
+     *    ' -> '
+     *
+     * See also OutSupport.writeEscapedXml().
+     */
+    public static String escapeXml(String buffer) {
+        int start = 0;
+        int length = buffer.length();
+        char[] arrayBuffer = buffer.toCharArray();
+        StringBuffer escapedBuffer = null;
+
+        for (int i = 0; i < length; i++) {
+            char c = arrayBuffer[i];
+            if (c <= HIGHEST_SPECIAL) {
+                char[] escaped = specialCharactersRepresentation[c];
+                if (escaped != null) {
+                    // create StringBuffer to hold escaped xml string
+                    if (start == 0) {
+                        escapedBuffer = new StringBuffer(length + 5);
+                    }
+                    // add unescaped portion
+                    if (start < i) {
+                        escapedBuffer.append(arrayBuffer,start,i-start);
+                    }
+                    start = i + 1;
+                    // add escaped xml
+                    escapedBuffer.append(escaped);
+                }
+            }
+        }
+        // no xml escaping was necessary
+        if (start == 0) {
+            return buffer;
+        }
+        // add rest of unescaped portion
+        if (start < length) {
+            escapedBuffer.append(arrayBuffer,start,length-start);
+        }
+        return escapedBuffer.toString();
+    }
+
+    /**
+     * Get the value associated with a content-type attribute.
+     * Syntax defined in RFC 2045, section 5.1.
+     */
+    public static String getContentTypeAttribute(String input, String name) {
+	int begin;
+	int end;
+        int index = input.toUpperCase().indexOf(name.toUpperCase());
+        if (index == -1) return null;
+        index = index + name.length(); // positioned after the attribute name
+        index = input.indexOf('=', index); // positioned at the '='
+        if (index == -1) return null;
+        index += 1; // positioned after the '='
+        input = input.substring(index).trim();
+        
+        if (input.charAt(0) == '"') {
+            // attribute value is a quoted string
+            begin = 1;
+            end = input.indexOf('"', begin);
+            if (end == -1) return null;
+        } else {
+            begin = 0;
+            end = input.indexOf(';');
+            if (end == -1) end = input.indexOf(' ');
+            if (end == -1) end = input.length();
+        }
+        return input.substring(begin, end).trim();
+    }
+    
+    /**
+     * URL encodes a string, based on the supplied character encoding.
+     * This performs the same function as java.next.URLEncode.encode
+     * in J2SDK1.4, and should be removed if the only platform supported
+     * is 1.4 or higher.
+     * @param s The String to be URL encoded.
+     * @param enc The character encoding 
+     * @return The URL encoded String
+     * [taken from jakarta-tomcat-jasper/jasper2
+     *  org.apache.jasper.runtime.JspRuntimeLibrary.java]
+     */
+    public static String URLEncode(String s, String enc) {
+
+	if (s == null) {
+	    return "null";
+	}
+
+	if (enc == null) {
+	    enc = "UTF-8";	// Is this right?
+	}
+
+	StringBuffer out = new StringBuffer(s.length());
+	ByteArrayOutputStream buf = new ByteArrayOutputStream();
+	OutputStreamWriter writer = null;
+	try {
+	    writer = new OutputStreamWriter(buf, enc);
+	} catch (java.io.UnsupportedEncodingException ex) {
+	    // Use the default encoding?
+	    writer = new OutputStreamWriter(buf);
+	}
+	
+	for (int i = 0; i < s.length(); i++) {
+	    int c = s.charAt(i);
+	    if (c == ' ') {
+		out.append('+');
+	    } else if (isSafeChar(c)) {
+		out.append((char)c);
+	    } else {
+		// convert to external encoding before hex conversion
+		try {
+		    writer.write(c);
+		    writer.flush();
+		} catch(IOException e) {
+		    buf.reset();
+		    continue;
+		}
+		byte[] ba = buf.toByteArray();
+		for (int j = 0; j < ba.length; j++) {
+		    out.append('%');
+		    // Converting each byte in the buffer
+		    out.append(Character.forDigit((ba[j]>>4) & 0xf, 16));
+		    out.append(Character.forDigit(ba[j] & 0xf, 16));
+		}
+		buf.reset();
+	    }
+	}
+	return out.toString();
+    }
+
+    private static boolean isSafeChar(int c) {
+	if (c >= 'a' && c <= 'z') {
+	    return true;
+	}
+	if (c >= 'A' && c <= 'Z') {
+	    return true;
+	}
+	if (c >= '0' && c <= '9') {
+	    return true;
+	}
+	if (c == '-' || c == '_' || c == '.' || c == '!' ||
+	    c == '~' || c == '*' || c == '\'' || c == '(' || c == ')') {
+	    return true;
+	}
+	return false;
+    }    
+    
+    /**
+     * HttpServletRequest.getLocales() returns the server's default locale 
+     * if the request did not specify a preferred language.
+     * We do not want this behavior, because it prevents us from using
+     * the fallback locale. 
+     * We therefore need to return an empty Enumeration if no preferred 
+     * locale has been specified. This way, the logic for the fallback 
+     * locale will be able to kick in.
+     */
+    public static Enumeration getRequestLocales(HttpServletRequest request) {        
+        Enumeration values = request.getHeaders("accept-language");
+        if (values.hasMoreElements()) {
+            // At least one "accept-language". Simply return
+            // the enumeration returned by request.getLocales().
+            // System.out.println("At least one accept-language");
+            return request.getLocales();
+        } else {
+            // No header for "accept-language". Simply return
+            // the empty enumeration.
+            // System.out.println("No accept-language");
+            return values;
+        }
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/common/core/WhenTagSupport.java b/standard/src/org/apache/taglibs/standard/tag/common/core/WhenTagSupport.java
new file mode 100644
index 0000000..86658cd
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/common/core/WhenTagSupport.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.common.core;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.JspTagException;
+import javax.servlet.jsp.jstl.core.ConditionalTagSupport;
+import javax.servlet.jsp.tagext.Tag;
+
+import org.apache.taglibs.standard.resources.Resources;
+
+/**
+ * <p>WhenTagSupport is an abstract class that facilitates
+ * implementation of <when>-style tags in both the rtexprvalue
+ * and expression-evaluating libraries.  It also supports
+ * <otherwise>.</p>
+ *
+ * <p>In particular, this base class does the following:</p>
+ * 
+ * <ul>
+ *  <li> overrides ConditionalTagSupport.doStartTag() to implement the
+ *       appropriate semantics of subtags of <choose> </li>
+ * </ul>
+ *
+ * @author Shawn Bayern
+ */
+public abstract class WhenTagSupport extends ConditionalTagSupport
+{
+    //*********************************************************************
+    // Implementation of exclusive-conditional behavior
+
+    /*
+     * Includes its body if condition() evalutes to true AND its parent
+     * ChooseTag wants it to do so.  The condition will not even be
+     * evaluated if ChooseTag instructs us not to run.
+     */
+    public int doStartTag() throws JspException {
+
+        Tag parent;
+
+        // make sure we're contained properly
+        if (!((parent = getParent()) instanceof ChooseTag))
+            throw new JspTagException(
+		Resources.getMessage("WHEN_OUTSIDE_CHOOSE"));
+
+        // make sure our parent wants us to continue
+        if (!((ChooseTag) parent).gainPermission())
+            return SKIP_BODY;                   // we've been reeled in
+
+        // handle conditional behavior
+        if (condition()) {
+            ((ChooseTag) parent).subtagSucceeded();
+            return EVAL_BODY_INCLUDE;
+        } else
+            return SKIP_BODY;
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/common/fmt/BundleSupport.java b/standard/src/org/apache/taglibs/standard/tag/common/fmt/BundleSupport.java
new file mode 100644
index 0000000..c8f832e
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/common/fmt/BundleSupport.java
@@ -0,0 +1,328 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.common.fmt;
+
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Locale;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.JspTagException;
+import javax.servlet.jsp.PageContext;
+import javax.servlet.jsp.jstl.core.Config;
+import javax.servlet.jsp.jstl.fmt.LocalizationContext;
+import javax.servlet.jsp.tagext.BodyTagSupport;
+
+import org.apache.taglibs.standard.tag.common.core.Util;
+
+/**
+ * Support for tag handlers for <bundle>, the resource bundle loading
+ * tag in JSTL 1.0.
+ *
+ * @author Jan Luehe
+ */
+
+public abstract class BundleSupport extends BodyTagSupport {
+    
+
+    //*********************************************************************
+    // Private constants
+
+    private static final Locale EMPTY_LOCALE = new Locale("", "");
+
+
+    //*********************************************************************
+    // Protected state
+
+    protected String basename;                  // 'basename' attribute
+    protected String prefix;                    // 'prefix' attribute
+
+
+    //*********************************************************************
+    // Private state
+
+    private Locale fallbackLocale;
+    private LocalizationContext locCtxt;
+
+
+    //*********************************************************************
+    // Constructor and initialization
+
+    public BundleSupport() {
+	super();
+	init();
+    }
+
+    private void init() {
+	basename = prefix = null;
+	locCtxt = null;
+    }
+
+    
+    //*********************************************************************
+    // Collaboration with subtags
+
+    public LocalizationContext getLocalizationContext() {
+	return locCtxt;
+    }
+
+    public String getPrefix() {
+	return prefix;
+    }
+
+
+    //*********************************************************************
+    // Tag logic
+
+    public int doStartTag() throws JspException {
+	locCtxt = getLocalizationContext(pageContext, basename);
+	return EVAL_BODY_BUFFERED;
+    }
+
+    public int doEndTag() throws JspException {
+	if (bodyContent != null) {
+	    try {
+		pageContext.getOut().print(bodyContent.getString());
+	    } catch (IOException ioe) {
+		throw new JspTagException(ioe.toString(), ioe);
+	    }
+	}
+
+	return EVAL_PAGE;
+    }
+
+    // Releases any resources we may have (or inherit)
+    public void release() {
+	init();
+    }
+
+
+    //*********************************************************************
+    // Public utility methods
+
+    /**
+     * Gets the default I18N localization context.
+     *
+     * @param pc Page in which to look up the default I18N localization context
+     */    
+    public static LocalizationContext getLocalizationContext(PageContext pc) {
+	LocalizationContext locCtxt = null;
+
+	Object obj = Config.find(pc, Config.FMT_LOCALIZATION_CONTEXT);
+	if (obj == null) {
+	    return null;
+	}
+
+	if (obj instanceof LocalizationContext) {
+	    locCtxt = (LocalizationContext) obj;
+	} else {
+	    // localization context is a bundle basename
+	    locCtxt = getLocalizationContext(pc, (String) obj);
+	}
+
+	return locCtxt;
+    }
+
+    /**
+     * Gets the resource bundle with the given base name, whose locale is
+     * determined as follows:
+     *
+     * Check if a match exists between the ordered set of preferred
+     * locales and the available locales, for the given base name.
+     * The set of preferred locales consists of a single locale
+     * (if the <tt>javax.servlet.jsp.jstl.fmt.locale</tt> configuration
+     * setting is present) or is equal to the client's preferred locales
+     * determined from the client's browser settings.
+     *
+     * <p> If no match was found in the previous step, check if a match
+     * exists between the fallback locale (given by the
+     * <tt>javax.servlet.jsp.jstl.fmt.fallbackLocale</tt> configuration
+     * setting) and the available locales, for the given base name.
+     *
+     * @param pageContext Page in which the resource bundle with the
+     * given base name is requested
+     * @param basename Resource bundle base name
+     *
+     * @return Localization context containing the resource bundle with the
+     * given base name and the locale that led to the resource bundle match,
+     * or the empty localization context if no resource bundle match was found
+     */
+    public static LocalizationContext getLocalizationContext(PageContext pc,
+							     String basename) {
+	LocalizationContext locCtxt = null;
+	ResourceBundle bundle = null;
+
+	if ((basename == null) || basename.equals("")) {
+	    return new LocalizationContext();
+	}
+
+	// Try preferred locales
+	Locale pref = SetLocaleSupport.getLocale(pc, Config.FMT_LOCALE);
+	if (pref != null) {
+	    // Preferred locale is application-based
+	    bundle = findMatch(basename, pref);
+	    if (bundle != null) {
+		locCtxt = new LocalizationContext(bundle, pref);
+	    }
+	} else {
+	    // Preferred locales are browser-based
+	    locCtxt = findMatch(pc, basename);
+	}
+	
+	if (locCtxt == null) {
+	    // No match found with preferred locales, try using fallback locale
+	    pref = SetLocaleSupport.getLocale(pc, Config.FMT_FALLBACK_LOCALE);
+	    if (pref != null) {
+		bundle = findMatch(basename, pref);
+		if (bundle != null) {
+		    locCtxt = new LocalizationContext(bundle, pref);
+		}
+	    }
+	}
+
+	if (locCtxt == null) {
+	    // try using the root resource bundle with the given basename
+	    try {
+		bundle = ResourceBundle.getBundle(basename, EMPTY_LOCALE,
+						  Thread.currentThread().getContextClassLoader());
+		if (bundle != null) {
+		    locCtxt = new LocalizationContext(bundle, null);
+		}
+	    } catch (MissingResourceException mre) {
+		// do nothing
+	    }
+	}
+		 
+	if (locCtxt != null) {
+	    // set response locale
+	    if (locCtxt.getLocale() != null) {
+		SetLocaleSupport.setResponseLocale(pc, locCtxt.getLocale());
+	    }
+	} else {
+	    // create empty localization context
+	    locCtxt = new LocalizationContext();
+	}
+
+	return locCtxt;
+    }
+
+
+    //*********************************************************************
+    // Private utility methods
+    
+    /*
+     * Determines the client's preferred locales from the request, and compares
+     * each of the locales (in order of preference) against the available
+     * locales in order to determine the best matching locale.
+     *
+     * @param pageContext the page in which the resource bundle with the
+     * given base name is requested
+     * @param basename the resource bundle's base name
+     *
+     * @return the localization context containing the resource bundle with
+     * the given base name and best matching locale, or <tt>null</tt> if no
+     * resource bundle match was found
+     */
+    private static LocalizationContext findMatch(PageContext pageContext,
+						 String basename) {
+	LocalizationContext locCtxt = null;
+	
+	// Determine locale from client's browser settings.
+        
+	for (Enumeration enum_ = Util.getRequestLocales((HttpServletRequest)pageContext.getRequest());
+	     enum_.hasMoreElements(); ) {
+	    Locale pref = (Locale) enum_.nextElement();
+	    ResourceBundle match = findMatch(basename, pref);
+	    if (match != null) {
+		locCtxt = new LocalizationContext(match, pref);
+		break;
+	    }
+	}
+        	
+	return locCtxt;
+    }
+
+    /*
+     * Gets the resource bundle with the given base name and preferred locale.
+     * 
+     * This method calls java.util.ResourceBundle.getBundle(), but ignores
+     * its return value unless its locale represents an exact or language match
+     * with the given preferred locale.
+     *
+     * @param basename the resource bundle base name
+     * @param pref the preferred locale
+     *
+     * @return the requested resource bundle, or <tt>null</tt> if no resource
+     * bundle with the given base name exists or if there is no exact- or
+     * language-match between the preferred locale and the locale of
+     * the bundle returned by java.util.ResourceBundle.getBundle().
+     */
+    private static ResourceBundle findMatch(String basename, Locale pref) {
+	ResourceBundle match = null;
+
+	try {
+	    ResourceBundle bundle =
+		ResourceBundle.getBundle(basename, pref,
+					 Thread.currentThread().getContextClassLoader());
+	    Locale avail = bundle.getLocale();
+	    if (pref.equals(avail)) {
+		// Exact match
+		match = bundle;
+	    } else {
+                /*
+                 * We have to make sure that the match we got is for
+                 * the specified locale. The way ResourceBundle.getBundle()
+                 * works, if a match is not found with (1) the specified locale,
+                 * it tries to match with (2) the current default locale as 
+                 * returned by Locale.getDefault() or (3) the root resource 
+                 * bundle (basename).
+                 * We must ignore any match that could have worked with (2) or (3).
+                 * So if an exact match is not found, we make the following extra
+                 * tests:
+                 *     - avail locale must be equal to preferred locale
+                 *     - avail country must be empty or equal to preferred country
+                 *       (the equality match might have failed on the variant)
+		 */
+                if (pref.getLanguage().equals(avail.getLanguage())
+		    && ("".equals(avail.getCountry()) || pref.getCountry().equals(avail.getCountry()))) {
+		    /*
+		     * Language match.
+		     * By making sure the available locale does not have a 
+		     * country and matches the preferred locale's language, we
+		     * rule out "matches" based on the container's default
+		     * locale. For example, if the preferred locale is 
+		     * "en-US", the container's default locale is "en-UK", and
+		     * there is a resource bundle (with the requested base
+		     * name) available for "en-UK", ResourceBundle.getBundle()
+		     * will return it, but even though its language matches
+		     * that of the preferred locale, we must ignore it,
+		     * because matches based on the container's default locale
+		     * are not portable across different containers with
+		     * different default locales.
+		     */
+		    match = bundle;
+		}
+	    }
+	} catch (MissingResourceException mre) {
+	}
+
+	return match;
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/common/fmt/FormatDateSupport.java b/standard/src/org/apache/taglibs/standard/tag/common/fmt/FormatDateSupport.java
new file mode 100644
index 0000000..7c83fa2
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/common/fmt/FormatDateSupport.java
@@ -0,0 +1,207 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.common.fmt;
+
+import java.io.IOException;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.JspTagException;
+import javax.servlet.jsp.PageContext;
+import javax.servlet.jsp.tagext.TagSupport;
+
+import org.apache.taglibs.standard.resources.Resources;
+import org.apache.taglibs.standard.tag.common.core.Util;
+
+/**
+ * Support for tag handlers for <formatDate>, the date and time
+ * formatting tag in JSTL 1.0.
+ *
+ * @author Jan Luehe
+ */
+
+public abstract class FormatDateSupport extends TagSupport {
+
+    //*********************************************************************
+    // Private constants
+
+    private static final String DATE = "date";
+    private static final String TIME = "time";
+    private static final String DATETIME = "both";
+
+
+    //*********************************************************************
+    // Protected state
+
+    protected Date value;                        // 'value' attribute
+    protected String type;                       // 'type' attribute
+    protected String pattern;                    // 'pattern' attribute
+    protected Object timeZone;                   // 'timeZone' attribute
+    protected String dateStyle;                  // 'dateStyle' attribute
+    protected String timeStyle;                  // 'timeStyle' attribute
+
+
+    //*********************************************************************
+    // Private state
+
+    private String var;                          // 'var' attribute
+    private int scope;                           // 'scope' attribute
+
+
+    //*********************************************************************
+    // Constructor and initialization
+
+    public FormatDateSupport() {
+	super();
+	init();
+    }
+
+    private void init() {
+	type = dateStyle = timeStyle = null;
+	pattern = var = null;
+	value = null;
+	timeZone = null;
+	scope = PageContext.PAGE_SCOPE;
+    }
+
+
+   //*********************************************************************
+    // Tag attributes known at translation time
+
+    public void setVar(String var) {
+        this.var = var;
+    }
+
+    public void setScope(String scope) {
+	this.scope = Util.getScope(scope);
+    }
+
+
+    //*********************************************************************
+    // Tag logic
+
+    /*
+     * Formats the given date and time.
+     */
+    public int doEndTag() throws JspException {
+
+	String formatted = null;
+
+	if (value == null) {
+	    if (var != null) {
+		pageContext.removeAttribute(var, scope);
+	    }
+	    return EVAL_PAGE;
+	}
+
+	// Create formatter
+	Locale locale = SetLocaleSupport.getFormattingLocale(
+            pageContext,
+	    this,
+	    true,
+	    DateFormat.getAvailableLocales());
+
+	if (locale != null) {
+	    DateFormat formatter = createFormatter(locale);
+
+	    // Apply pattern, if present
+	    if (pattern != null) {
+		try {
+		    ((SimpleDateFormat) formatter).applyPattern(pattern);
+		} catch (ClassCastException cce) {
+		    formatter = new SimpleDateFormat(pattern, locale);
+		}
+	    }
+
+	    // Set time zone
+	    TimeZone tz = null;
+	    if ((timeZone instanceof String)
+		&& ((String) timeZone).equals("")) {
+		timeZone = null;
+	    }
+	    if (timeZone != null) {
+		if (timeZone instanceof String) {
+		    tz = TimeZone.getTimeZone((String) timeZone);
+		} else if (timeZone instanceof TimeZone) {
+		    tz = (TimeZone) timeZone;
+		} else {
+		    throw new JspTagException(
+                            Resources.getMessage("FORMAT_DATE_BAD_TIMEZONE"));
+		}
+	    } else {
+		tz = TimeZoneSupport.getTimeZone(pageContext, this);
+	    }
+	    if (tz != null) {
+		formatter.setTimeZone(tz);
+	    }
+	    formatted = formatter.format(value);
+	} else {
+	    // no formatting locale available, use Date.toString()
+	    formatted = value.toString();
+	}
+
+	if (var != null) {
+	    pageContext.setAttribute(var, formatted, scope);	
+	} else {
+	    try {
+		pageContext.getOut().print(formatted);
+	    } catch (IOException ioe) {
+		throw new JspTagException(ioe.toString(), ioe);
+	    }
+	}
+
+	return EVAL_PAGE;
+    }
+
+    // Releases any resources we may have (or inherit)
+    public void release() {
+	init();
+    }
+
+
+    //*********************************************************************
+    // Private utility methods
+
+    private DateFormat createFormatter(Locale loc) throws JspException {
+	DateFormat formatter = null;
+
+	if ((type == null) || DATE.equalsIgnoreCase(type)) {
+	    formatter = DateFormat.getDateInstance(
+	        Util.getStyle(dateStyle, "FORMAT_DATE_INVALID_DATE_STYLE"),
+		loc);
+	} else if (TIME.equalsIgnoreCase(type)) {
+	    formatter = DateFormat.getTimeInstance(
+	        Util.getStyle(timeStyle, "FORMAT_DATE_INVALID_TIME_STYLE"),
+		loc);
+	} else if (DATETIME.equalsIgnoreCase(type)) {
+	    formatter = DateFormat.getDateTimeInstance(
+	        Util.getStyle(dateStyle, "FORMAT_DATE_INVALID_DATE_STYLE"),
+		Util.getStyle(timeStyle, "FORMAT_DATE_INVALID_TIME_STYLE"),
+		loc);
+	} else {
+	    throw new JspException(
+                    Resources.getMessage("FORMAT_DATE_INVALID_TYPE", 
+					 type));
+	}
+
+	return formatter;
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/common/fmt/FormatNumberSupport.java b/standard/src/org/apache/taglibs/standard/tag/common/fmt/FormatNumberSupport.java
new file mode 100644
index 0000000..27cb1b6
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/common/fmt/FormatNumberSupport.java
@@ -0,0 +1,338 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.common.fmt;
+
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.text.NumberFormat;
+import java.util.Locale;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.JspTagException;
+import javax.servlet.jsp.PageContext;
+import javax.servlet.jsp.tagext.BodyTagSupport;
+
+import org.apache.taglibs.standard.resources.Resources;
+import org.apache.taglibs.standard.tag.common.core.Util;
+
+/**
+ * Support for tag handlers for <formatNumber>, the number
+ * formatting tag in JSTL 1.0.
+ *
+ * @author Jan Luehe
+ */
+
+public abstract class FormatNumberSupport extends BodyTagSupport {
+
+    //*********************************************************************
+    // Private constants
+
+    private static final Class[] GET_INSTANCE_PARAM_TYPES =
+	new Class[] { String.class };
+    private static final String NUMBER = "number";    
+    private static final String CURRENCY = "currency";
+    private static final String PERCENT = "percent";
+
+
+    //*********************************************************************
+    // Protected state
+
+    protected Object value;                    // 'value' attribute
+    protected boolean valueSpecified;	       // status
+    protected String type;                     // 'type' attribute
+    protected String pattern;                  // 'pattern' attribute
+    protected String currencyCode;             // 'currencyCode' attribute
+    protected String currencySymbol;           // 'currencySymbol' attribute
+    protected boolean isGroupingUsed;          // 'groupingUsed' attribute
+    protected boolean groupingUsedSpecified;
+    protected int maxIntegerDigits;            // 'maxIntegerDigits' attribute
+    protected boolean maxIntegerDigitsSpecified;
+    protected int minIntegerDigits;            // 'minIntegerDigits' attribute
+    protected boolean minIntegerDigitsSpecified;
+    protected int maxFractionDigits;           // 'maxFractionDigits' attribute
+    protected boolean maxFractionDigitsSpecified;
+    protected int minFractionDigits;           // 'minFractionDigits' attribute
+    protected boolean minFractionDigitsSpecified;
+
+
+    //*********************************************************************
+    // Private state
+
+    private String var;                        // 'var' attribute
+    private int scope;                         // 'scope' attribute
+    private static Class currencyClass;
+
+
+    //*********************************************************************
+    // Constructor and initialization
+
+    static {
+	try {
+	    currencyClass = Class.forName("java.util.Currency");
+	    // container's runtime is J2SE 1.4 or greater
+	} catch (Exception cnfe) {
+	}
+    }
+
+    public FormatNumberSupport() {
+	super();
+	init();
+    }
+
+    private void init() {
+	value = type = null;
+	valueSpecified = false;
+	pattern = var = currencyCode = currencySymbol = null;
+	groupingUsedSpecified = false;
+	maxIntegerDigitsSpecified = minIntegerDigitsSpecified = false;
+	maxFractionDigitsSpecified = minFractionDigitsSpecified = false;
+	scope = PageContext.PAGE_SCOPE;
+    }
+
+
+   //*********************************************************************
+    // Tag attributes known at translation time
+
+    public void setVar(String var) {
+        this.var = var;
+    }
+
+    public void setScope(String scope) {
+	this.scope = Util.getScope(scope);
+    }
+
+
+    //*********************************************************************
+    // Tag logic
+
+    public int doEndTag() throws JspException {
+	String formatted = null;
+        Object input = null;
+
+        // determine the input by...
+        if (valueSpecified) {
+	    // ... reading 'value' attribute
+	    input = value;
+	} else {
+	    // ... retrieving and trimming our body
+	    if (bodyContent != null && bodyContent.getString() != null)
+	        input = bodyContent.getString().trim();
+	}
+
+	if ((input == null) || input.equals("")) {
+	    // Spec says:
+            // If value is null or empty, remove the scoped variable 
+            // if it is specified (see attributes var and scope).
+	    if (var != null) {
+	        pageContext.removeAttribute(var, scope);
+            }
+	    return EVAL_PAGE;
+	}
+
+	/*
+	 * If 'value' is a String, it is first parsed into an instance of
+	 * java.lang.Number
+	 */
+	if (input instanceof String) {
+	    try {
+		if (((String) input).indexOf('.') != -1) {
+		    input = Double.valueOf((String) input);
+		} else {
+		    input = Long.valueOf((String) input);
+		}
+	    } catch (NumberFormatException nfe) {
+		throw new JspException(
+                    Resources.getMessage("FORMAT_NUMBER_PARSE_ERROR", input),
+		    nfe);
+	    }
+	}
+
+	// Determine formatting locale
+	Locale loc = SetLocaleSupport.getFormattingLocale(
+            pageContext,
+	    this,
+	    true,
+	    NumberFormat.getAvailableLocales());
+
+	if (loc != null) {
+	    // Create formatter 
+	    NumberFormat formatter = null;
+	    if ((pattern != null) && !pattern.equals("")) {
+		// if 'pattern' is specified, 'type' is ignored
+		DecimalFormatSymbols symbols = new DecimalFormatSymbols(loc);
+		formatter = new DecimalFormat(pattern, symbols);
+	    } else {
+		formatter = createFormatter(loc);
+	    }
+	    if (((pattern != null) && !pattern.equals(""))
+		    || CURRENCY.equalsIgnoreCase(type)) {
+		try {
+		    setCurrency(formatter);
+		} catch (Exception e) {
+		    throw new JspException(
+                        Resources.getMessage("FORMAT_NUMBER_CURRENCY_ERROR"),
+			e);
+		}
+	    }
+	    configureFormatter(formatter);
+	    formatted = formatter.format(input);
+	} else {
+	    // no formatting locale available, use toString()
+	    formatted = input.toString();
+	}
+
+	if (var != null) {
+	    pageContext.setAttribute(var, formatted, scope);	
+	} else {
+	    try {
+		pageContext.getOut().print(formatted);
+	    } catch (IOException ioe) {
+		throw new JspTagException(ioe.toString(), ioe);
+	    }
+	}
+
+	return EVAL_PAGE;
+    }
+
+    // Releases any resources we may have (or inherit)
+    public void release() {
+	init();
+    }
+
+
+    //*********************************************************************
+    // Private utility methods
+
+    private NumberFormat createFormatter(Locale loc) throws JspException {
+	NumberFormat formatter = null;
+	
+	if ((type == null) || NUMBER.equalsIgnoreCase(type)) {
+	    formatter = NumberFormat.getNumberInstance(loc);
+	} else if (CURRENCY.equalsIgnoreCase(type)) {
+	    formatter = NumberFormat.getCurrencyInstance(loc);
+	} else if (PERCENT.equalsIgnoreCase(type)) {
+	    formatter = NumberFormat.getPercentInstance(loc);
+	} else {
+	    throw new JspException(
+	        Resources.getMessage("FORMAT_NUMBER_INVALID_TYPE", type));
+	}
+	
+	return formatter;
+    }
+
+    /*
+     * Applies the 'groupingUsed', 'maxIntegerDigits', 'minIntegerDigits',
+     * 'maxFractionDigits', and 'minFractionDigits' attributes to the given
+     * formatter.
+     */
+    private void configureFormatter(NumberFormat formatter) {
+	if (groupingUsedSpecified)
+	    formatter.setGroupingUsed(isGroupingUsed);
+	if (maxIntegerDigitsSpecified)
+	    formatter.setMaximumIntegerDigits(maxIntegerDigits);
+	if (minIntegerDigitsSpecified)
+	    formatter.setMinimumIntegerDigits(minIntegerDigits);
+	if (maxFractionDigitsSpecified)
+	    formatter.setMaximumFractionDigits(maxFractionDigits);
+	if (minFractionDigitsSpecified)
+	    formatter.setMinimumFractionDigits(minFractionDigits);
+    }
+
+    /*
+     * Override the formatting locale's default currency symbol with the
+     * specified currency code (specified via the "currencyCode" attribute) or
+     * currency symbol (specified via the "currencySymbol" attribute).
+     *
+     * If both "currencyCode" and "currencySymbol" are present,
+     * "currencyCode" takes precedence over "currencySymbol" if the
+     * java.util.Currency class is defined in the container's runtime (that
+     * is, if the container's runtime is J2SE 1.4 or greater), and
+     * "currencySymbol" takes precendence over "currencyCode" otherwise.
+     *
+     * If only "currencyCode" is given, it is used as a currency symbol if
+     * java.util.Currency is not defined.
+     *
+     * Example:
+     *
+     * JDK    "currencyCode" "currencySymbol" Currency symbol being displayed
+     * -----------------------------------------------------------------------
+     * all         ---            ---         Locale's default currency symbol
+     *
+     * <1.4        EUR            ---         EUR
+     * >=1.4       EUR            ---         Locale's currency symbol for Euro
+     *
+     * all         ---           \u20AC       \u20AC
+     * 
+     * <1.4        EUR           \u20AC       \u20AC
+     * >=1.4       EUR           \u20AC       Locale's currency symbol for Euro
+     */
+    private void setCurrency(NumberFormat formatter) throws Exception {
+	String code = null;
+	String symbol = null;
+
+	if ((currencyCode == null) && (currencySymbol == null)) {
+	    return;
+	}
+
+	if ((currencyCode != null) && (currencySymbol != null)) {
+	    if (currencyClass != null)
+		code = currencyCode;
+	    else
+		symbol = currencySymbol;
+	} else if (currencyCode == null) {
+	    symbol = currencySymbol;
+	} else {
+	    if (currencyClass != null)
+		code = currencyCode;
+	    else
+		symbol = currencyCode;
+	}
+
+	if (code != null) {
+	    Object[] methodArgs = new Object[1];
+
+	    /*
+	     * java.util.Currency.getInstance()
+	     */
+	    Method m = currencyClass.getMethod("getInstance",
+					       GET_INSTANCE_PARAM_TYPES);
+	    methodArgs[0] = code;
+	    Object currency = m.invoke(null, methodArgs);
+
+	    /*
+	     * java.text.NumberFormat.setCurrency()
+	     */
+	    Class[] paramTypes = new Class[1];
+	    paramTypes[0] = currencyClass;
+	    Class numberFormatClass = Class.forName("java.text.NumberFormat");
+	    m = numberFormatClass.getMethod("setCurrency", paramTypes);
+	    methodArgs[0] = currency;
+	    m.invoke(formatter, methodArgs);
+	} else {
+	    /*
+	     * Let potential ClassCastException propagate up (will almost
+	     * never happen)
+	     */
+	    DecimalFormat df = (DecimalFormat) formatter;
+	    DecimalFormatSymbols dfs = df.getDecimalFormatSymbols();
+	    dfs.setCurrencySymbol(symbol);
+	    df.setDecimalFormatSymbols(dfs);
+	}
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/common/fmt/MessageSupport.java b/standard/src/org/apache/taglibs/standard/tag/common/fmt/MessageSupport.java
new file mode 100644
index 0000000..b026c04
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/common/fmt/MessageSupport.java
@@ -0,0 +1,216 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.common.fmt;
+
+import java.io.IOException;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.JspTagException;
+import javax.servlet.jsp.PageContext;
+import javax.servlet.jsp.jstl.fmt.LocalizationContext;
+import javax.servlet.jsp.tagext.BodyTagSupport;
+import javax.servlet.jsp.tagext.Tag;
+
+import org.apache.taglibs.standard.tag.common.core.Util;
+
+/**
+ * Support for tag handlers for <message>, the message formatting tag
+ * in JSTL 1.0.
+ *
+ * @author Jan Luehe
+ */
+
+public abstract class MessageSupport extends BodyTagSupport {
+
+    //*********************************************************************
+    // Public constants
+
+    public static final String UNDEFINED_KEY = "???";
+
+
+    //*********************************************************************
+    // Protected state
+
+    protected String keyAttrValue;       // 'key' attribute value
+    protected boolean keySpecified;	 // 'key' attribute specified
+    protected LocalizationContext bundleAttrValue; // 'bundle' attribute value
+    protected boolean bundleSpecified;   // 'bundle' attribute specified?
+
+
+    //*********************************************************************
+    // Private state
+
+    private String var;                           // 'var' attribute
+    private int scope;                            // 'scope' attribute
+    private List params;
+
+
+    //*********************************************************************
+    // Constructor and initialization
+
+    public MessageSupport() {
+	super();
+	params = new ArrayList();
+	init();
+    }
+
+    private void init() {
+	var = null;
+	scope = PageContext.PAGE_SCOPE;
+	keyAttrValue = null;
+	keySpecified = false;
+	bundleAttrValue = null;
+	bundleSpecified = false;
+    }
+
+
+    //*********************************************************************
+    // Tag attributes known at translation time
+
+    public void setVar(String var) {
+        this.var = var;
+    }
+
+    public void setScope(String scope) {
+	this.scope = Util.getScope(scope);
+    }
+
+
+    //*********************************************************************
+    // Collaboration with subtags
+
+    /**
+     * Adds an argument (for parametric replacement) to this tag's message.
+     *
+     * @see ParamSupport
+     */
+    public void addParam(Object arg) {
+	params.add(arg);
+    }
+
+
+    //*********************************************************************
+    // Tag logic
+
+    public int doStartTag() throws JspException {
+	params.clear();
+	return EVAL_BODY_BUFFERED;
+    }
+
+    public int doEndTag() throws JspException {
+
+        String key = null;
+	LocalizationContext locCtxt = null;
+
+        // determine the message key by...
+        if (keySpecified) {
+	    // ... reading 'key' attribute
+	    key = keyAttrValue;
+	} else {
+	    // ... retrieving and trimming our body
+	    if (bodyContent != null && bodyContent.getString() != null)
+	        key = bodyContent.getString().trim();
+	}
+
+	if ((key == null) || key.equals("")) {
+	    try {
+		pageContext.getOut().print("??????");
+	    } catch (IOException ioe) {
+		throw new JspTagException(ioe.toString(), ioe);
+	    }
+	    return EVAL_PAGE;
+	}
+
+	String prefix = null;
+	if (!bundleSpecified) {
+	    Tag t = findAncestorWithClass(this, BundleSupport.class);
+	    if (t != null) {
+		// use resource bundle from parent <bundle> tag
+		BundleSupport parent = (BundleSupport) t;
+		locCtxt = parent.getLocalizationContext();
+		prefix = parent.getPrefix();
+	    } else {
+		locCtxt = BundleSupport.getLocalizationContext(pageContext);
+	    }
+	} else {
+	    // localization context taken from 'bundle' attribute
+	    locCtxt = bundleAttrValue;
+	    if (locCtxt.getLocale() != null) {
+		SetLocaleSupport.setResponseLocale(pageContext,
+						   locCtxt.getLocale());
+	    }
+	}
+        
+ 	String message = UNDEFINED_KEY + key + UNDEFINED_KEY;
+	if (locCtxt != null) {
+	    ResourceBundle bundle = locCtxt.getResourceBundle();
+	    if (bundle != null) {
+		try {
+		    // prepend 'prefix' attribute from parent bundle
+		    if (prefix != null)
+			key = prefix + key;
+		    message = bundle.getString(key);
+		    // Perform parametric replacement if required
+		    if (!params.isEmpty()) {
+			Object[] messageArgs = params.toArray();
+			MessageFormat formatter = new MessageFormat(""); // empty pattern, default Locale
+			if (locCtxt.getLocale() != null) {
+			    formatter.setLocale(locCtxt.getLocale());
+			} else {
+                            // For consistency with the <fmt:formatXXX> actions,
+                            // we try to get a locale that matches the user's preferences
+                            // as well as the locales supported by 'date' and 'number'.
+                            //System.out.println("LOCALE-LESS LOCCTXT: GETTING FORMATTING LOCALE");
+                            Locale locale = SetLocaleSupport.getFormattingLocale(pageContext);
+                            //System.out.println("LOCALE: " + locale);
+                            if (locale != null) {
+                                formatter.setLocale(locale);
+                            }
+                        }
+			formatter.applyPattern(message);
+			message = formatter.format(messageArgs);
+		    }
+		} catch (MissingResourceException mre) {
+		    message = UNDEFINED_KEY + key + UNDEFINED_KEY;
+		}
+	    }
+	}
+
+	if (var != null) {
+	    pageContext.setAttribute(var, message, scope);	
+	} else {
+	    try {
+		pageContext.getOut().print(message);
+	    } catch (IOException ioe) {
+		throw new JspTagException(ioe.toString(), ioe);
+	    }
+	}
+
+	return EVAL_PAGE;
+    }
+
+    // Releases any resources we may have (or inherit)
+    public void release() {
+	init();
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/common/fmt/ParamSupport.java b/standard/src/org/apache/taglibs/standard/tag/common/fmt/ParamSupport.java
new file mode 100755
index 0000000..ff6169c
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/common/fmt/ParamSupport.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.common.fmt;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.JspTagException;
+import javax.servlet.jsp.tagext.BodyTagSupport;
+import javax.servlet.jsp.tagext.Tag;
+
+import org.apache.taglibs.standard.resources.Resources;
+
+/**
+ * Support for tag handlers for <param>, the message argument
+ * subtag in JSTL 1.0 which supplies an argument for parametric replacement
+ * to its parent <message> tag.
+ *
+ * @see MessageSupport
+ * @author Jan Luehe
+ */
+
+public abstract class ParamSupport extends BodyTagSupport {
+
+    //*********************************************************************
+    // Protected state
+
+    protected Object value;                          // 'value' attribute
+    protected boolean valueSpecified;	             // status
+
+
+    //*********************************************************************
+    // Constructor and initialization
+
+    public ParamSupport() {
+	super();
+	init();
+    }
+
+    private void init() {
+	value = null;
+	valueSpecified = false;
+    }
+
+
+    //*********************************************************************
+    // Tag logic
+
+    // Supply our value to our parent <fmt:message> tag
+    public int doEndTag() throws JspException {
+	Tag t = findAncestorWithClass(this, MessageSupport.class);
+	if (t == null) {
+	    throw new JspTagException(Resources.getMessage(
+                            "PARAM_OUTSIDE_MESSAGE"));
+	}
+	MessageSupport parent = (MessageSupport) t;
+
+	/*
+	 * Get argument from 'value' attribute or body, as appropriate, and
+	 * add it to enclosing <fmt:message> tag, even if it is null or equal
+	 * to "".
+	 */
+	Object input = null;
+        // determine the input by...
+	if (valueSpecified) {
+	    // ... reading 'value' attribute
+	    input = value;
+	} else {
+	    // ... retrieving and trimming our body (TLV has ensured that it's
+	    // non-empty)
+	    input = bodyContent.getString().trim();
+	}
+	parent.addParam(input);
+
+	return EVAL_PAGE;
+    }
+
+    // Releases any resources we may have (or inherit)
+    public void release() {
+	init();
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/common/fmt/ParseDateSupport.java b/standard/src/org/apache/taglibs/standard/tag/common/fmt/ParseDateSupport.java
new file mode 100644
index 0000000..3f6f1b6
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/common/fmt/ParseDateSupport.java
@@ -0,0 +1,232 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.common.fmt;
+
+import java.io.IOException;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.JspTagException;
+import javax.servlet.jsp.PageContext;
+import javax.servlet.jsp.tagext.BodyTagSupport;
+
+import org.apache.taglibs.standard.resources.Resources;
+import org.apache.taglibs.standard.tag.common.core.Util;
+
+/**
+ * Support for tag handlers for <parseDate>, the date and time
+ * parsing tag in JSTL 1.0.
+ *
+ * @author Jan Luehe
+ */
+
+public abstract class ParseDateSupport extends BodyTagSupport {
+
+    //*********************************************************************
+    // Private constants
+
+    private static final String DATE = "date";
+    private static final String TIME = "time";
+    private static final String DATETIME = "both";
+
+
+    //*********************************************************************
+    // Protected state
+
+    protected String value;                      // 'value' attribute
+    protected boolean valueSpecified;	         // status
+    protected String type;                       // 'type' attribute
+    protected String pattern;                    // 'pattern' attribute
+    protected Object timeZone;                   // 'timeZone' attribute
+    protected Locale parseLocale;                // 'parseLocale' attribute
+    protected String dateStyle;                  // 'dateStyle' attribute
+    protected String timeStyle;                  // 'timeStyle' attribute
+
+
+    //*********************************************************************
+    // Private state
+
+    private String var;                          // 'var' attribute
+    private int scope;                           // 'scope' attribute
+
+
+    //*********************************************************************
+    // Constructor and initialization
+
+    public ParseDateSupport() {
+	super();
+	init();
+    }
+
+    private void init() {
+	type = dateStyle = timeStyle = null;
+	value = pattern = var = null;
+	valueSpecified = false;
+	timeZone = null;
+	scope = PageContext.PAGE_SCOPE;
+	parseLocale = null;
+    }
+
+
+   //*********************************************************************
+    // Tag attributes known at translation time
+
+    public void setVar(String var) {
+        this.var = var;
+    }
+
+    public void setScope(String scope) {
+	this.scope = Util.getScope(scope);
+    }
+
+
+    //*********************************************************************
+    // Tag logic
+
+    public int doEndTag() throws JspException {
+
+        String input = null;
+
+        // determine the input by...
+        if (valueSpecified) {
+	    // ... reading 'value' attribute
+	    input = value;
+	} else {
+	    // ... retrieving and trimming our body
+	    if (bodyContent != null && bodyContent.getString() != null)
+	        input = bodyContent.getString().trim();
+	}
+
+	if ((input == null) || input.equals("")) {
+	    if (var != null) {
+		pageContext.removeAttribute(var, scope);
+	    }
+	    return EVAL_PAGE;
+	}
+
+	/*
+	 * Set up parsing locale: Use locale specified via the 'parseLocale'
+	 * attribute (if present), or else determine page's locale.
+	 */
+	Locale locale = parseLocale;
+	if (locale == null)
+	    locale = SetLocaleSupport.getFormattingLocale(
+                pageContext,
+	        this,
+		false,
+	        DateFormat.getAvailableLocales());
+	if (locale == null) {
+	    throw new JspException(
+                    Resources.getMessage("PARSE_DATE_NO_PARSE_LOCALE"));
+	}
+
+	// Create parser
+	DateFormat parser = createParser(locale);
+
+	// Apply pattern, if present
+	if (pattern != null) {
+	    try {
+		((SimpleDateFormat) parser).applyPattern(pattern);
+	    } catch (ClassCastException cce) {
+		parser = new SimpleDateFormat(pattern, locale);
+	    }
+	}
+
+	// Set time zone
+	TimeZone tz = null;
+	if ((timeZone instanceof String) && ((String) timeZone).equals("")) {
+	    timeZone = null;
+	}
+	if (timeZone != null) {
+	    if (timeZone instanceof String) {
+		tz = TimeZone.getTimeZone((String) timeZone);
+	    } else if (timeZone instanceof TimeZone) {
+		tz = (TimeZone) timeZone;
+	    } else {
+		throw new JspException(
+                    Resources.getMessage("PARSE_DATE_BAD_TIMEZONE"));
+	    }
+	} else {
+	    tz = TimeZoneSupport.getTimeZone(pageContext, this);
+	}
+	if (tz != null) {
+	    parser.setTimeZone(tz);
+	}
+
+	// Parse date
+	Date parsed = null;
+	try {
+	    parsed = parser.parse(input);
+	} catch (ParseException pe) {
+	    throw new JspException(
+	            Resources.getMessage("PARSE_DATE_PARSE_ERROR", input),
+		    pe);
+	}
+
+	if (var != null) {
+	    pageContext.setAttribute(var, parsed, scope);	
+	} else {
+	    try {
+		pageContext.getOut().print(parsed);
+	    } catch (IOException ioe) {
+		throw new JspTagException(ioe.toString(), ioe);
+	    }
+	}
+
+	return EVAL_PAGE;
+    }
+
+    // Releases any resources we may have (or inherit)
+    public void release() {
+	init();
+    }
+
+
+    //*********************************************************************
+    // Private utility methods
+
+    private DateFormat createParser(Locale loc) throws JspException {
+	DateFormat parser = null;
+
+	if ((type == null) || DATE.equalsIgnoreCase(type)) {
+	    parser = DateFormat.getDateInstance(
+	        Util.getStyle(dateStyle, "PARSE_DATE_INVALID_DATE_STYLE"),
+		loc);
+	} else if (TIME.equalsIgnoreCase(type)) {
+	    parser = DateFormat.getTimeInstance(
+	        Util.getStyle(timeStyle, "PARSE_DATE_INVALID_TIME_STYLE"),
+		loc);
+	} else if (DATETIME.equalsIgnoreCase(type)) {
+	    parser = DateFormat.getDateTimeInstance(
+	        Util.getStyle(dateStyle, "PARSE_DATE_INVALID_DATE_STYLE"),
+		Util.getStyle(timeStyle, "PARSE_DATE_INVALID_TIME_STYLE"),
+		loc);
+	} else {
+	    throw new JspException(
+                    Resources.getMessage("PARSE_DATE_INVALID_TYPE", type));
+	}
+
+	parser.setLenient(false);
+
+	return parser;
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/common/fmt/ParseNumberSupport.java b/standard/src/org/apache/taglibs/standard/tag/common/fmt/ParseNumberSupport.java
new file mode 100644
index 0000000..afd299e
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/common/fmt/ParseNumberSupport.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.common.fmt;
+
+import java.io.IOException;
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.text.NumberFormat;
+import java.text.ParseException;
+import java.util.Locale;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.JspTagException;
+import javax.servlet.jsp.PageContext;
+import javax.servlet.jsp.tagext.BodyTagSupport;
+
+import org.apache.taglibs.standard.resources.Resources;
+import org.apache.taglibs.standard.tag.common.core.Util;
+
+/**
+ * Support for tag handlers for <parseNumber>, the number parsing tag
+ * in JSTL 1.0.
+ *
+ * @author Jan Luehe
+ */
+
+public abstract class ParseNumberSupport extends BodyTagSupport {
+
+    //*********************************************************************
+    // Private constants
+
+    private static final String NUMBER = "number";    
+    private static final String CURRENCY = "currency";
+    private static final String PERCENT = "percent";
+
+
+    //*********************************************************************
+    // Protected state
+
+    protected String value;                      // 'value' attribute
+    protected boolean valueSpecified;	         // status
+    protected String type;                       // 'type' attribute
+    protected String pattern;                    // 'pattern' attribute
+    protected Locale parseLocale;                // 'parseLocale' attribute
+    protected boolean isIntegerOnly;             // 'integerOnly' attribute
+    protected boolean integerOnlySpecified;
+
+
+    //*********************************************************************
+    // Private state
+
+    private String var;                          // 'var' attribute
+    private int scope;                           // 'scope' attribute
+
+
+    //*********************************************************************
+    // Constructor and initialization
+
+    public ParseNumberSupport() {
+	super();
+	init();
+    }
+
+    private void init() {
+	value = type = pattern = var = null;
+	valueSpecified = false;
+	parseLocale = null;
+	integerOnlySpecified = false;
+	scope = PageContext.PAGE_SCOPE;
+    }
+
+
+   //*********************************************************************
+    // Tag attributes known at translation time
+
+    public void setVar(String var) {
+        this.var = var;
+    }
+
+    public void setScope(String scope) {
+	this.scope = Util.getScope(scope);
+    }
+
+
+    //*********************************************************************
+    // Tag logic
+
+    public int doEndTag() throws JspException {
+	String input = null;
+
+        // determine the input by...
+	if (valueSpecified) {
+	    // ... reading 'value' attribute
+	    input = value;
+	} else {
+	    // ... retrieving and trimming our body
+	    if (bodyContent != null && bodyContent.getString() != null)
+	        input = bodyContent.getString().trim();
+	}
+
+	if ((input == null) || input.equals("")) {
+	    if (var != null) {
+		pageContext.removeAttribute(var, scope);
+	    }
+	    return EVAL_PAGE;
+	}
+
+	/*
+	 * Set up parsing locale: Use locale specified via the 'parseLocale'
+	 * attribute (if present), or else determine page's locale.
+	 */
+	Locale loc = parseLocale;
+	if (loc == null)
+	    loc = SetLocaleSupport.getFormattingLocale(
+                pageContext,
+	        this,
+		false,
+	        NumberFormat.getAvailableLocales());
+	if (loc == null) {
+	    throw new JspException(
+                    Resources.getMessage("PARSE_NUMBER_NO_PARSE_LOCALE"));
+	}
+
+	// Create parser
+	NumberFormat parser = null;
+	if ((pattern != null) && !pattern.equals("")) {
+	    // if 'pattern' is specified, 'type' is ignored
+	    DecimalFormatSymbols symbols = new DecimalFormatSymbols(loc);
+	    parser = new DecimalFormat(pattern, symbols);
+	} else {
+	    parser = createParser(loc);
+	}
+
+	// Configure parser
+	if (integerOnlySpecified)
+	    parser.setParseIntegerOnly(isIntegerOnly);
+
+	// Parse number
+	Number parsed = null;
+	try {
+	    parsed = parser.parse(input);
+	} catch (ParseException pe) {
+	    throw new JspException(
+	            Resources.getMessage("PARSE_NUMBER_PARSE_ERROR", input),
+		    pe);
+	}
+
+	if (var != null) {
+	    pageContext.setAttribute(var, parsed, scope);	
+	} else {
+	    try {
+		pageContext.getOut().print(parsed);
+	    } catch (IOException ioe) {
+		throw new JspTagException(ioe.toString(), ioe);
+	    }
+	}
+
+	return EVAL_PAGE;
+    }
+
+    // Releases any resources we may have (or inherit)
+    public void release() {
+	init();
+    }
+
+
+    //*********************************************************************
+    // Private utility methods
+
+    private NumberFormat createParser(Locale loc) throws JspException {
+	NumberFormat parser = null;
+
+	if ((type == null) || NUMBER.equalsIgnoreCase(type)) {
+	    parser = NumberFormat.getNumberInstance(loc);
+	} else if (CURRENCY.equalsIgnoreCase(type)) {
+	    parser = NumberFormat.getCurrencyInstance(loc);
+	} else if (PERCENT.equalsIgnoreCase(type)) {
+	    parser = NumberFormat.getPercentInstance(loc);
+	} else {
+	    throw new JspException(
+                    Resources.getMessage("PARSE_NUMBER_INVALID_TYPE", 
+					 type));
+	}
+
+	return parser;
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/common/fmt/RequestEncodingSupport.java b/standard/src/org/apache/taglibs/standard/tag/common/fmt/RequestEncodingSupport.java
new file mode 100644
index 0000000..42058c2
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/common/fmt/RequestEncodingSupport.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.common.fmt;
+
+import java.io.UnsupportedEncodingException;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.JspTagException;
+import javax.servlet.jsp.PageContext;
+import javax.servlet.jsp.tagext.TagSupport;
+
+/**
+ * Support for tag handlers for <requestEncoding>, the tag for setting
+ * the request character encoding in JSTL 1.0.
+ *
+ * @author Jan Luehe
+ * @author Pierre Delisle
+ */
+
+public abstract class RequestEncodingSupport extends TagSupport {
+
+    //*********************************************************************
+    // Package-scoped constants
+
+    static final String REQUEST_CHAR_SET =
+	"javax.servlet.jsp.jstl.fmt.request.charset";
+
+
+    //*********************************************************************
+    // Private constants
+
+    private static final String DEFAULT_ENCODING = "ISO-8859-1";
+
+
+    //*********************************************************************
+    // Tag attributes
+
+    protected String value;             // 'value' attribute
+    
+
+    //*********************************************************************
+    // Derived information
+    
+    protected String charEncoding;   // derived from 'value' attribute  
+    
+
+    //*********************************************************************
+    // Constructor and initialization
+
+    public RequestEncodingSupport() {
+	super();
+	init();
+    }
+
+    private void init() {
+	value = null;
+    }
+
+
+    //*********************************************************************
+    // Tag logic
+
+    public int doEndTag() throws JspException {
+        charEncoding = value;
+	if ((charEncoding == null)
+	        && (pageContext.getRequest().getCharacterEncoding() == null)) { 
+            // Use charset from session-scoped attribute
+	    charEncoding = (String)
+		pageContext.getAttribute(REQUEST_CHAR_SET,
+					 PageContext.SESSION_SCOPE);
+	    if (charEncoding == null) {
+		// Use default encoding
+		charEncoding = DEFAULT_ENCODING;
+	    }
+	}
+
+	/*
+	 * If char encoding was already set in the request, we don't need to 
+	 * set it again.
+	 */
+	if (charEncoding != null) {
+	    try {
+		pageContext.getRequest().setCharacterEncoding(charEncoding);
+	    } catch (UnsupportedEncodingException uee) {
+		throw new JspTagException(uee.toString(), uee);
+	    }
+	}
+
+	return EVAL_PAGE;
+    }
+
+    // Releases any resources we may have (or inherit)
+    public void release() {
+	init();
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/common/fmt/SetBundleSupport.java b/standard/src/org/apache/taglibs/standard/tag/common/fmt/SetBundleSupport.java
new file mode 100644
index 0000000..dbb681e
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/common/fmt/SetBundleSupport.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.common.fmt;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.PageContext;
+import javax.servlet.jsp.jstl.core.Config;
+import javax.servlet.jsp.jstl.fmt.LocalizationContext;
+import javax.servlet.jsp.tagext.TagSupport;
+
+import org.apache.taglibs.standard.tag.common.core.Util;
+
+/**
+ * Support for tag handlers for <setBundle>, the JSTL 1.0 tag that loads
+ * a resource bundle and stores it in a scoped variable.
+ *
+ * @author Jan Luehe
+ */
+
+public abstract class SetBundleSupport extends TagSupport {
+
+    
+    //*********************************************************************
+    // Protected state
+
+    protected String basename;                  // 'basename' attribute
+
+
+    //*********************************************************************
+    // Private state
+
+    private int scope;                          // 'scope' attribute
+    private String var;                         // 'var' attribute
+
+
+    //*********************************************************************
+    // Constructor and initialization
+
+    public SetBundleSupport() {
+	super();
+	init();
+    }
+
+    private void init() {
+	basename = null;
+	scope = PageContext.PAGE_SCOPE;
+    }
+
+
+    //*********************************************************************
+    // Tag attributes known at translation time
+
+    public void setVar(String var) {
+        this.var = var;
+    }
+
+    public void setScope(String scope) {
+	this.scope = Util.getScope(scope);
+    }
+
+
+    //*********************************************************************
+    // Tag logic
+
+    public int doEndTag() throws JspException {
+	LocalizationContext locCtxt =
+	    BundleSupport.getLocalizationContext(pageContext, basename);
+
+	if (var != null) {
+	    pageContext.setAttribute(var, locCtxt, scope);
+	} else {
+	    Config.set(pageContext, Config.FMT_LOCALIZATION_CONTEXT, locCtxt,
+		       scope);
+	}
+
+	return EVAL_PAGE;
+    }
+
+    // Releases any resources we may have (or inherit)
+    public void release() {
+	init();
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/common/fmt/SetLocaleSupport.java b/standard/src/org/apache/taglibs/standard/tag/common/fmt/SetLocaleSupport.java
new file mode 100644
index 0000000..6058492
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/common/fmt/SetLocaleSupport.java
@@ -0,0 +1,463 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.common.fmt;
+
+import java.text.DateFormat;
+import java.text.NumberFormat;
+import java.util.Enumeration;
+import java.util.Locale;
+import java.util.Vector;
+
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.PageContext;
+import javax.servlet.jsp.jstl.core.Config;
+import javax.servlet.jsp.jstl.fmt.LocalizationContext;
+import javax.servlet.jsp.tagext.Tag;
+import javax.servlet.jsp.tagext.TagSupport;
+
+import org.apache.taglibs.standard.resources.Resources;
+import org.apache.taglibs.standard.tag.common.core.Util;
+
+/**
+ * Support for tag handlers for <setLocale>, the locale setting tag in
+ * JSTL 1.0.
+ *
+ * @author Jan Luehe
+ */
+
+public abstract class SetLocaleSupport extends TagSupport {
+
+    
+    //*********************************************************************
+    // Private constants
+
+    private static final char HYPHEN = '-';
+    private static final char UNDERSCORE = '_';
+
+
+    //*********************************************************************
+    // Protected state
+
+    protected Object value;                      // 'value' attribute
+    protected String variant;                    // 'variant' attribute
+
+
+    //*********************************************************************
+    // Private state
+
+    private int scope;                           // 'scope' attribute
+
+
+    //*********************************************************************
+    // Constructor and initialization
+
+    public SetLocaleSupport() {
+	super();
+	init();
+    }
+
+    private void init() {
+	value = variant = null;
+	scope = PageContext.PAGE_SCOPE;
+    }
+
+
+   //*********************************************************************
+    // Tag attributes known at translation time
+
+    public void setScope(String scope) {
+	this.scope = Util.getScope(scope);
+    }
+
+
+    //*********************************************************************
+    // Tag logic
+
+    public int doEndTag() throws JspException {
+	Locale locale = null;
+
+	if (value == null) {
+	    locale = Locale.getDefault();
+	} else if (value instanceof String) {
+	    if (((String) value).trim().equals("")) {
+		locale = Locale.getDefault();
+	    } else {
+		locale = parseLocale((String) value, variant);
+	    }
+	} else {
+	    locale = (Locale) value;
+	}
+
+	Config.set(pageContext, Config.FMT_LOCALE, locale, scope);
+	setResponseLocale(pageContext, locale);
+
+	return EVAL_PAGE;
+    }
+
+    // Releases any resources we may have (or inherit)
+    public void release() {
+	init();
+    }
+
+
+    //*********************************************************************
+    // Public utility methods
+
+    /**
+     * See parseLocale(String, String) for details.
+     */
+    public static Locale parseLocale(String locale) {
+	return parseLocale(locale, null);
+    }
+
+    /**
+     * Parses the given locale string into its language and (optionally)
+     * country components, and returns the corresponding
+     * <tt>java.util.Locale</tt> object.
+     *
+     * If the given locale string is null or empty, the runtime's default
+     * locale is returned.
+     *
+     * @param locale the locale string to parse
+     * @param variant the variant
+     *
+     * @return <tt>java.util.Locale</tt> object corresponding to the given
+     * locale string, or the runtime's default locale if the locale string is
+     * null or empty
+     *
+     * @throws IllegalArgumentException if the given locale does not have a
+     * language component or has an empty country component
+     */
+    public static Locale parseLocale(String locale, String variant) {
+
+	Locale ret = null;
+	String language = locale;
+	String country = null;
+	int index = -1;
+
+	if (((index = locale.indexOf(HYPHEN)) > -1)
+	        || ((index = locale.indexOf(UNDERSCORE)) > -1)) {
+	    language = locale.substring(0, index);
+	    country = locale.substring(index+1);
+	}
+
+	if ((language == null) || (language.length() == 0)) {
+	    throw new IllegalArgumentException(
+		Resources.getMessage("LOCALE_NO_LANGUAGE"));
+	}
+
+	if (country == null) {
+	    if (variant != null)
+		ret = new Locale(language, "", variant);
+	    else
+		ret = new Locale(language, "");
+	} else if (country.length() > 0) {
+	    if (variant != null)
+		ret = new Locale(language, country, variant);
+	    else
+		ret = new Locale(language, country);
+	} else {
+	    throw new IllegalArgumentException(
+		Resources.getMessage("LOCALE_EMPTY_COUNTRY"));
+	}
+
+	return ret;
+    }
+
+
+    //*********************************************************************
+    // Package-scoped utility methods
+
+    /*
+     * Stores the given locale in the response object of the given page
+     * context, and stores the locale's associated charset in the
+     * javax.servlet.jsp.jstl.fmt.request.charset session attribute, which
+     * may be used by the <requestEncoding> action in a page invoked by a
+     * form included in the response to set the request charset to the same as
+     * the response charset (this makes it possible for the container to
+     * decode the form parameter values properly, since browsers typically
+     * encode form field values using the response's charset).
+     *
+     * @param pageContext the page context whose response object is assigned
+     * the given locale
+     * @param locale the response locale
+     */
+    static void setResponseLocale(PageContext pc, Locale locale) {
+	// set response locale
+	ServletResponse response = pc.getResponse();
+	response.setLocale(locale);
+	
+	// get response character encoding and store it in session attribute
+	if (pc.getSession() != null) {
+            try {
+	        pc.setAttribute(RequestEncodingSupport.REQUEST_CHAR_SET,
+			    response.getCharacterEncoding(),
+			    PageContext.SESSION_SCOPE);
+            } catch (IllegalStateException ex) {} // invalidated session ignored
+	}
+    }
+ 
+    /*
+     * Returns the formatting locale to use with the given formatting action
+     * in the given page.
+     *
+     * @param pc The page context containing the formatting action
+     * @param fromTag The formatting action
+     * @param format <tt>true</tt> if the formatting action is of type
+     * <formatXXX> (as opposed to <parseXXX>), and <tt>false</tt> otherwise
+     * (if set to <tt>true</tt>, the formatting locale that is returned by
+     * this method is used to set the response locale).
+     *
+     * @param avail the array of available locales
+     *
+     * @return the formatting locale to use
+     */
+    static Locale getFormattingLocale(PageContext pc,
+				      Tag fromTag,
+				      boolean format,
+				      Locale[] avail) {
+
+	LocalizationContext locCtxt = null;
+	
+	// Get formatting locale from enclosing <fmt:bundle>
+	Tag parent = findAncestorWithClass(fromTag, BundleSupport.class);
+	if (parent != null) {
+	    /*
+	     * use locale from localization context established by parent
+	     * <fmt:bundle> action, unless that locale is null
+	     */
+	    locCtxt = ((BundleSupport) parent).getLocalizationContext();
+	    if (locCtxt.getLocale() != null) {
+		if (format) {
+		    setResponseLocale(pc, locCtxt.getLocale());
+		}
+		return locCtxt.getLocale();
+	    }
+	}
+
+	// Use locale from default I18N localization context, unless it is null
+	if ((locCtxt = BundleSupport.getLocalizationContext(pc)) != null) {
+	    if (locCtxt.getLocale() != null) {
+		if (format) {
+		    setResponseLocale(pc, locCtxt.getLocale());
+		}
+		return locCtxt.getLocale();
+	    }
+	}
+
+	/*
+	 * Establish formatting locale by comparing the preferred locales
+	 * (in order of preference) against the available formatting
+	 * locales, and determining the best matching locale.
+	 */
+	Locale match = null;
+	Locale pref = getLocale(pc, Config.FMT_LOCALE);
+	if (pref != null) {
+	    // Preferred locale is application-based
+	    match = findFormattingMatch(pref, avail);
+	} else {
+	    // Preferred locales are browser-based 
+	    match = findFormattingMatch(pc, avail);
+	}
+	if (match == null) {
+	    //Use fallback locale.
+	    pref = getLocale(pc, Config.FMT_FALLBACK_LOCALE);
+	    if (pref != null) {
+		match = findFormattingMatch(pref, avail);
+	    }
+	}
+ 	if (format && (match != null)) {
+	    setResponseLocale(pc, match);
+	}
+
+	return match;
+    }
+
+    /**
+     * Setup the available formatting locales that will be used
+     * by getFormattingLocale(PageContext).
+     */
+    static Locale[] availableFormattingLocales;
+    static {
+        Locale[] dateLocales = DateFormat.getAvailableLocales();
+        Locale[] numberLocales = NumberFormat.getAvailableLocales();
+        Vector vec = new Vector(dateLocales.length);
+        for (int i=0; i<dateLocales.length; i++) {
+            for (int j=0; j<numberLocales.length; j++) {
+                if (dateLocales[i].equals(numberLocales[j])) {
+                    vec.add(dateLocales[i]);
+                    break;
+                }
+            }
+        }
+        availableFormattingLocales = new Locale[vec.size()];
+        availableFormattingLocales = (Locale[])vec.toArray(availableFormattingLocales);
+        /*
+        for (int i=0; i<availableFormattingLocales.length; i++) {
+            System.out.println("AvailableLocale[" + i + "] " + availableFormattingLocales[i]);
+        }
+        */
+    }
+    
+    /*
+     * Returns the formatting locale to use when <fmt:message> is used
+     * with a locale-less localization context.
+     *
+     * @param pc The page context containing the formatting action
+     * @return the formatting locale to use
+     */
+    static Locale getFormattingLocale(PageContext pc) {
+	/*
+	 * Establish formatting locale by comparing the preferred locales
+	 * (in order of preference) against the available formatting
+	 * locales, and determining the best matching locale.
+	 */
+	Locale match = null;
+	Locale pref = getLocale(pc, Config.FMT_LOCALE);
+	if (pref != null) {
+	    // Preferred locale is application-based
+	    match = findFormattingMatch(pref, availableFormattingLocales);
+	} else {
+	    // Preferred locales are browser-based 
+	    match = findFormattingMatch(pc, availableFormattingLocales);
+	}
+	if (match == null) {
+	    //Use fallback locale.
+	    pref = getLocale(pc, Config.FMT_FALLBACK_LOCALE);
+	    if (pref != null) {
+		match = findFormattingMatch(pref, availableFormattingLocales);
+	    }
+	}
+ 	if (match != null) {
+	    setResponseLocale(pc, match);
+	}
+
+	return match;
+    }
+
+    /*
+     * Returns the locale specified by the named scoped attribute or context
+     * configuration parameter.
+     *
+     * <p> The named scoped attribute is searched in the page, request,
+     * session (if valid), and application scope(s) (in this order). If no such
+     * attribute exists in any of the scopes, the locale is taken from the
+     * named context configuration parameter.
+     *
+     * @param pageContext the page in which to search for the named scoped
+     * attribute or context configuration parameter
+     * @param name the name of the scoped attribute or context configuration
+     * parameter
+     *
+     * @return the locale specified by the named scoped attribute or context
+     * configuration parameter, or <tt>null</tt> if no scoped attribute or
+     * configuration parameter with the given name exists
+     */
+    static Locale getLocale(PageContext pageContext, String name) {
+	Locale loc = null;
+
+	Object obj = Config.find(pageContext, name);
+	if (obj != null) {
+	    if (obj instanceof Locale) {
+		loc = (Locale) obj;
+	    } else {
+		loc = parseLocale((String) obj);
+	    }
+	}
+
+	return loc;
+    }
+
+
+    //*********************************************************************
+    // Private utility methods
+
+    /*
+     * Determines the client's preferred locales from the request, and compares
+     * each of the locales (in order of preference) against the available
+     * locales in order to determine the best matching locale.
+     *
+     * @param pageContext Page containing the formatting action
+     * @param avail Available formatting locales
+     *
+     * @return Best matching locale, or <tt>null</tt> if no match was found
+     */
+    private static Locale findFormattingMatch(PageContext pageContext,
+					      Locale[] avail) {
+	Locale match = null;
+	for (Enumeration enum_ = Util.getRequestLocales((HttpServletRequest)pageContext.getRequest());
+	     enum_.hasMoreElements(); ) {
+            Locale locale = (Locale)enum_.nextElement();
+	    match = findFormattingMatch(locale, avail);
+	    if (match != null) {
+		break;
+	    }
+	}
+	
+	return match;
+    }
+
+    /*
+     * Returns the best match between the given preferred locale and the
+     * given available locales.
+     *
+     * The best match is given as the first available locale that exactly
+     * matches the given preferred locale ("exact match"). If no exact match
+     * exists, the best match is given to an available locale that meets
+     * the following criteria (in order of priority):
+     *  - available locale's variant is empty and exact match for both
+     *    language and country
+     *  - available locale's variant and country are empty, and exact match 
+     *    for language.
+     *
+     * @param pref the preferred locale
+     * @param avail the available formatting locales
+     *
+     * @return Available locale that best matches the given preferred locale,
+     * or <tt>null</tt> if no match exists
+     */
+    private static Locale findFormattingMatch(Locale pref, Locale[] avail) {
+	Locale match = null;
+        boolean langAndCountryMatch = false;
+        for (int i=0; i<avail.length; i++) {
+            if (pref.equals(avail[i])) {
+                // Exact match
+                match = avail[i];
+                break;
+            } else if (
+                    !"".equals(pref.getVariant()) &&
+                    "".equals(avail[i].getVariant()) &&
+                    pref.getLanguage().equals(avail[i].getLanguage()) &&
+                    pref.getCountry().equals(avail[i].getCountry())) {
+                // Language and country match; different variant
+                match = avail[i];
+                langAndCountryMatch = true;
+            } else if (
+                    !langAndCountryMatch &&
+                    pref.getLanguage().equals(avail[i].getLanguage()) &&
+                    ("".equals(avail[i].getCountry()))) {
+                // Language match
+                if (match == null) {
+                    match = avail[i];
+                }
+            }
+        }
+	return match;
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/common/fmt/SetTimeZoneSupport.java b/standard/src/org/apache/taglibs/standard/tag/common/fmt/SetTimeZoneSupport.java
new file mode 100644
index 0000000..926d3ac
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/common/fmt/SetTimeZoneSupport.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.common.fmt;
+
+import java.util.TimeZone;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.PageContext;
+import javax.servlet.jsp.jstl.core.Config;
+import javax.servlet.jsp.tagext.TagSupport;
+
+import org.apache.taglibs.standard.tag.common.core.Util;
+
+/**
+ * Support for tag handlers for <setTimeZone>, the time zone setting tag
+ * in JSTL 1.0.
+ *
+ * @author Jan Luehe
+ */
+
+public abstract class SetTimeZoneSupport extends TagSupport {
+
+    
+    //*********************************************************************
+    // Protected state
+
+    protected Object value;                      // 'value' attribute
+
+
+    //*********************************************************************
+    // Private state
+
+    private int scope;                           // 'scope' attribute
+    private String var;                          // 'var' attribute
+
+
+    //*********************************************************************
+    // Constructor and initialization
+
+    public SetTimeZoneSupport() {
+	super();
+	init();
+    }
+
+    // resets local state
+    private void init() {
+	value = var = null;
+	scope = PageContext.PAGE_SCOPE;
+    }
+
+
+   //*********************************************************************
+    // Tag attributes known at translation time
+
+    public void setScope(String scope) {
+	this.scope = Util.getScope(scope);
+    }
+
+    public void setVar(String var) {
+        this.var = var;
+    }
+
+
+    //*********************************************************************
+    // Tag logic
+
+    public int doEndTag() throws JspException {
+	TimeZone timeZone = null;
+
+	if (value == null) {
+	    timeZone = TimeZone.getTimeZone("GMT");
+	} else if (value instanceof String) {
+	    if (((String) value).trim().equals("")) {
+		timeZone = TimeZone.getTimeZone("GMT");
+	    } else {
+		timeZone = TimeZone.getTimeZone((String) value);
+	    }
+	} else {
+	    timeZone = (TimeZone) value;
+	}
+
+	if (var != null) {
+	    pageContext.setAttribute(var, timeZone, scope);
+	} else {
+	    Config.set(pageContext, Config.FMT_TIME_ZONE, timeZone, scope);
+	}
+
+	return EVAL_PAGE;
+    }
+
+    // Releases any resources we may have (or inherit)
+    public void release() {
+	init();
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/common/fmt/TimeZoneSupport.java b/standard/src/org/apache/taglibs/standard/tag/common/fmt/TimeZoneSupport.java
new file mode 100644
index 0000000..dcea441
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/common/fmt/TimeZoneSupport.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.common.fmt;
+
+import java.io.IOException;
+import java.util.TimeZone;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.JspTagException;
+import javax.servlet.jsp.PageContext;
+import javax.servlet.jsp.jstl.core.Config;
+import javax.servlet.jsp.tagext.BodyTagSupport;
+import javax.servlet.jsp.tagext.Tag;
+
+/**
+ * Support for tag handlers for <timeZone>, the time zone tag in
+ * JSTL 1.0.
+ *
+ * @author Jan Luehe
+ */
+
+public abstract class TimeZoneSupport extends BodyTagSupport {
+
+
+    //*********************************************************************
+    // Protected state
+
+    protected Object value;                      // 'value' attribute
+  
+
+    //*********************************************************************
+    // Private state
+
+    private TimeZone timeZone;
+
+
+    //*********************************************************************
+    // Constructor and initialization
+
+    public TimeZoneSupport() {
+	super();
+	init();
+    }
+
+    private void init() {
+	value = null;
+    }
+
+
+    //*********************************************************************
+    // Collaboration with subtags
+
+    public TimeZone getTimeZone() {
+	return timeZone;
+    }
+
+
+    //*********************************************************************
+    // Tag logic
+
+    public int doStartTag() throws JspException {
+
+	if (value == null) {
+	    timeZone = TimeZone.getTimeZone("GMT");
+	} else if (value instanceof String) {
+	    if (((String) value).trim().equals("")) {
+		timeZone = TimeZone.getTimeZone("GMT");
+	    } else {
+		timeZone = TimeZone.getTimeZone((String) value);
+	    }
+	} else {
+	    timeZone = (TimeZone) value;
+	}
+
+	return EVAL_BODY_BUFFERED;
+    }
+
+    public int doEndTag() throws JspException {
+	try {
+	    pageContext.getOut().print(bodyContent.getString());
+	} catch (IOException ioe) {
+	    throw new JspTagException(ioe.toString(), ioe);
+	}
+
+	return EVAL_PAGE;
+    }
+
+    // Releases any resources we may have (or inherit)
+    public void release() {
+	init();
+    }
+
+
+    //*********************************************************************
+    // Package-scoped utility methods
+
+    /*
+     * Determines and returns the time zone to be used by the given action.
+     *
+     * <p> If the given action is nested inside a <timeZone> action,
+     * the time zone is taken from the enclosing <timeZone> action.
+     *
+     * <p> Otherwise, the time zone configuration setting
+     * <tt>javax.servlet.jsp.jstl.core.Config.FMT_TIME_ZONE</tt>
+     * is used.
+     *
+     * @param pageContext the page containing the action for which the
+     * time zone needs to be determined
+     * @param fromTag the action for which the time zone needs to be
+     * determined
+     *
+     * @return the time zone, or <tt>null</tt> if the given action is not 
+     * nested inside a <timeZone> action and no time zone configuration
+     * setting exists
+     */
+    static TimeZone getTimeZone(PageContext pc, Tag fromTag) {
+	TimeZone tz = null;
+
+	Tag t = findAncestorWithClass(fromTag, TimeZoneSupport.class);
+	if (t != null) {
+	    // use time zone from parent <timeZone> tag
+	    TimeZoneSupport parent = (TimeZoneSupport) t;
+	    tz = parent.getTimeZone();
+	} else {
+	    // get time zone from configuration setting
+	    Object obj = Config.find(pc, Config.FMT_TIME_ZONE);
+	    if (obj != null) {
+		if (obj instanceof TimeZone) {
+		    tz = (TimeZone) obj;
+		} else {
+		    tz = TimeZone.getTimeZone((String) obj);
+		}
+	    }
+	}
+
+	return tz;
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/common/sql/DataSourceUtil.java b/standard/src/org/apache/taglibs/standard/tag/common/sql/DataSourceUtil.java
new file mode 100644
index 0000000..ea119e3
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/common/sql/DataSourceUtil.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.common.sql;
+
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.JspTagException;
+import javax.servlet.jsp.PageContext;
+import javax.servlet.jsp.jstl.core.Config;
+import javax.sql.DataSource;
+
+import org.apache.taglibs.standard.resources.Resources;
+
+
+/**
+ * <p>A simple <code>DataSource</code> utility for the standard
+ * <code>DriverManager</code> class.
+ *
+ * TO DO: need to cache DataSource
+ * 
+ * @author Justyna Horwat
+ */
+public class DataSourceUtil {
+
+    private static final String ESCAPE = "\\";
+    private static final String TOKEN = ",";
+
+    /**
+     * If dataSource is a String first do JNDI lookup.
+     * If lookup fails parse String like it was a set of JDBC parameters
+     * Otherwise check to see if dataSource is a DataSource object and use as
+     * is
+     */
+    static DataSource getDataSource(Object rawDataSource, PageContext pc)
+	throws JspException
+    {
+	DataSource dataSource = null;
+
+        if (rawDataSource == null) {
+            rawDataSource = Config.find(pc, Config.SQL_DATA_SOURCE);
+        }
+
+	if (rawDataSource == null) {
+	    return null;
+	}
+
+        /*
+	 * If the 'dataSource' attribute's value resolves to a String
+	 * after rtexpr/EL evaluation, use the string as JNDI path to
+	 * a DataSource
+	 */
+        if (rawDataSource instanceof String) {
+            try {
+                Context ctx = new InitialContext();
+                // relative to standard JNDI root for J2EE app
+                Context envCtx = (Context) ctx.lookup("java:comp/env");
+                dataSource = (DataSource) envCtx.lookup((String) rawDataSource);
+            } catch (NamingException ex) {
+                dataSource = getDataSource((String) rawDataSource);
+            }
+        } else if (rawDataSource instanceof DataSource) {
+            dataSource = (DataSource) rawDataSource;
+        } else {
+	    throw new JspException(
+                Resources.getMessage("SQL_DATASOURCE_INVALID_TYPE"));
+	}
+
+	return dataSource;
+    }
+
+    /**
+     * Parse JDBC parameters and setup dataSource appropriately
+     */
+    private static DataSource getDataSource(String params)
+	throws JspException
+    {
+        DataSourceWrapper dataSource = new DataSourceWrapper();
+
+        String[] paramString = new String[4];
+        int escCount = 0; 
+        int aryCount = 0; 
+        int begin = 0;
+
+        for(int index=0; index < params.length(); index++) {
+            char nextChar = params.charAt(index);
+            if (TOKEN.indexOf(nextChar) != -1) {
+                if (escCount == 0) {
+                    paramString[aryCount] = params.substring(begin,index).trim();
+                    begin = index + 1;
+                    if (++aryCount > 4) {
+                        throw new JspTagException(
+                            Resources.getMessage("JDBC_PARAM_COUNT"));
+                    }
+                }
+            }
+            if (ESCAPE.indexOf(nextChar) != -1) {
+                escCount++;
+            }
+            else {
+                escCount = 0;
+            }
+        }
+        paramString[aryCount] = params.substring(begin).trim();
+
+	// use the JDBC URL from the parameter string
+        dataSource.setJdbcURL(paramString[0]);
+
+	// try to load a driver if it's present
+        if (paramString[1] != null) {
+            try {
+                dataSource.setDriverClassName(paramString[1]);
+            } catch (Exception ex) {
+                throw new JspTagException(
+                    Resources.getMessage("DRIVER_INVALID_CLASS",
+					 ex.toString()), ex);
+            }
+	}
+
+	// set the username and password
+        dataSource.setUserName(paramString[2]);
+        dataSource.setPassword(paramString[3]);
+
+	return dataSource;
+    }
+
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/common/sql/DataSourceWrapper.java b/standard/src/org/apache/taglibs/standard/tag/common/sql/DataSourceWrapper.java
new file mode 100644
index 0000000..dbb8bfb
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/common/sql/DataSourceWrapper.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.common.sql;
+
+import java.io.PrintWriter;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+
+import javax.sql.DataSource;
+
+import org.apache.taglibs.standard.resources.Resources;
+
+
+/**
+ * <p>A simple <code>DataSource</code> wrapper for the standard
+ * <code>DriverManager</code> class.
+ * 
+ * @author Hans Bergsten
+ */
+public class DataSourceWrapper implements DataSource {
+    private String driverClassName;
+    private String jdbcURL;
+    private String userName;
+    private String password;
+
+    public void setDriverClassName(String driverClassName) 
+	throws ClassNotFoundException, InstantiationException, 
+	       IllegalAccessException {
+
+	this.driverClassName = driverClassName;
+        Class.forName(driverClassName, true, 
+            Thread.currentThread().getContextClassLoader()).newInstance();
+    }
+
+    public void setJdbcURL(String jdbcURL) {
+	this.jdbcURL = jdbcURL;
+    }
+
+    public void setUserName(String userName) {
+	this.userName = userName;
+    }
+
+    public void setPassword(String password) {
+	this.password = password;
+    }
+
+    /**
+     * Returns a Connection using the DriverManager and all
+     * set properties.
+     */
+    public Connection getConnection() throws SQLException {
+	Connection conn = null;
+	if (userName != null) {
+	    conn = DriverManager.getConnection(jdbcURL, userName, password);
+	}
+	else {
+	    conn = DriverManager.getConnection(jdbcURL);
+	}
+	return conn;
+    }
+
+    /**
+     * Always throws a SQLException. Username and password are set
+     * in the constructor and can not be changed.
+     */
+    public Connection getConnection(String username, String password) 
+            throws SQLException {
+        throw new SQLException(Resources.getMessage("NOT_SUPPORTED"));
+    }
+    
+    /**
+     * Always throws a SQLException. Not supported.
+     */
+    public int getLoginTimeout() throws SQLException {
+        throw new SQLException(Resources.getMessage("NOT_SUPPORTED"));
+    }
+    
+    /**
+     * Always throws a SQLException. Not supported.
+     */
+    public PrintWriter getLogWriter() throws SQLException {
+        throw new SQLException(Resources.getMessage("NOT_SUPPORTED"));
+    }
+    
+    /**
+     * Always throws a SQLException. Not supported.
+     */
+    public void setLoginTimeout(int seconds) throws SQLException {
+        throw new SQLException(Resources.getMessage("NOT_SUPPORTED"));
+    }
+    
+    /**
+     * Always throws a SQLException. Not supported.
+     */
+    public synchronized void setLogWriter(PrintWriter out) throws SQLException {
+        throw new SQLException(Resources.getMessage("NOT_SUPPORTED"));
+    }
+
+
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/common/sql/DateParamTagSupport.java b/standard/src/org/apache/taglibs/standard/tag/common/sql/DateParamTagSupport.java
new file mode 100644
index 0000000..2880c2a
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/common/sql/DateParamTagSupport.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.common.sql;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.JspTagException;
+import javax.servlet.jsp.jstl.sql.SQLExecutionTag;
+import javax.servlet.jsp.tagext.TagSupport;
+
+import org.apache.taglibs.standard.resources.Resources;
+
+
+/**
+ * <p>Tag handler for <Param> in JSTL, used to set
+ * parameter values for a SQL statement.</p>
+ * 
+ * @author Justyna Horwat
+ */
+
+public abstract class DateParamTagSupport extends TagSupport {
+
+    //*********************************************************************
+    // Private constants
+    
+    private static final String TIMESTAMP_TYPE = "timestamp";
+    private static final String TIME_TYPE = "time";
+    private static final String DATE_TYPE = "date";
+	
+
+    //*********************************************************************
+    // Protected state
+
+    protected String type;
+    protected java.util.Date value;
+
+
+    //*********************************************************************
+    // Constructor
+
+    public DateParamTagSupport() {
+        super();
+        init();
+    }
+
+    private void init() {
+        value = null;
+        type = null;
+    }
+
+
+    //*********************************************************************
+    // Tag logic
+
+    public int doEndTag() throws JspException {
+	SQLExecutionTag parent = (SQLExecutionTag) 
+	    findAncestorWithClass(this, SQLExecutionTag.class);
+	if (parent == null) {
+	    throw new JspTagException(
+                Resources.getMessage("SQL_PARAM_OUTSIDE_PARENT"));
+	}
+
+        if (value != null) {
+            convertValue();
+        }
+
+	parent.addSQLParameter(value);
+	return EVAL_PAGE;
+    }
+
+
+    //*********************************************************************
+    // Private utility methods
+
+    private void convertValue() throws JspException {
+
+	if ((type == null) || (type.equalsIgnoreCase(TIMESTAMP_TYPE))) {
+	    if (!(value instanceof java.sql.Timestamp)) {
+		value = new java.sql.Timestamp(value.getTime());
+	    }
+	} else if (type.equalsIgnoreCase(TIME_TYPE)) {
+	    if (!(value instanceof java.sql.Time)) {
+		value = new java.sql.Time(value.getTime());
+	    }
+	} else if (type.equalsIgnoreCase(DATE_TYPE)) {
+	    if (!(value instanceof java.sql.Date)) {
+		value = new java.sql.Date(value.getTime());
+	    }
+	} else {
+	    throw new JspException(
+                Resources.getMessage("SQL_DATE_PARAM_INVALID_TYPE", type));
+	}
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/common/sql/DriverTag.java b/standard/src/org/apache/taglibs/standard/tag/common/sql/DriverTag.java
new file mode 100644
index 0000000..2df890d
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/common/sql/DriverTag.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.common.sql;
+
+import javax.servlet.ServletContext;
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.JspTagException;
+import javax.servlet.jsp.PageContext;
+import javax.servlet.jsp.tagext.TagSupport;
+
+/**
+ * <p>Tag handler for <Driver> in JSTL, used to create
+ * a simple DataSource for prototyping.</p>
+ * 
+ * @author Hans Bergsten
+ */
+public class DriverTag extends TagSupport {
+    private static final String DRIVER_CLASS_NAME =
+	"javax.servlet.jsp.jstl.sql.driver";
+    private static final String JDBC_URL =
+	"javax.servlet.jsp.jstl.sql.jdbcURL";
+    private static final String USER_NAME =
+	"javax.servlet.jsp.jstl.sql.userName";
+    private static final String PASSWORD =
+	"javax.servlet.jsp.jstl.sql.password";
+
+    private String driverClassName;
+    private String jdbcURL;
+    private int scope = PageContext.PAGE_SCOPE;
+    private String userName;
+    private String var;
+
+    //*********************************************************************
+    // Accessor methods
+
+    public void setDriver(String driverClassName) {
+	this.driverClassName = driverClassName;
+    }
+
+    public void setJdbcURL(String jdbcURL) {
+	this.jdbcURL = jdbcURL;
+    }
+
+    /**
+     * Setter method for the scope of the variable to hold the
+     * result.
+     *
+     */
+    public void setScope(String scopeName) {
+        if ("page".equals(scopeName)) {
+            scope = PageContext.PAGE_SCOPE;
+        }
+        else if ("request".equals(scopeName)) {
+            scope = PageContext.REQUEST_SCOPE;
+        }
+        else if ("session".equals(scopeName)) {
+            scope = PageContext.SESSION_SCOPE;
+        }
+        else if ("application".equals(scopeName)) {
+            scope = PageContext.APPLICATION_SCOPE;
+        }
+    }
+
+    public void setUserName(String userName) {
+	this.userName = userName;
+    }
+
+    public void setVar(String var) {
+	this.var = var;
+    }
+
+    //*********************************************************************
+    // Tag logic
+
+    public int doStartTag() throws JspException {
+	DataSourceWrapper ds = new DataSourceWrapper();
+	try {
+	ds.setDriverClassName(getDriverClassName());
+	}
+	catch (Exception e) {
+	    throw new JspTagException("Invalid driver class name: " +
+		e.toString(), e);
+	}
+	ds.setJdbcURL(getJdbcURL());
+	ds.setUserName(getUserName());
+	ds.setPassword(getPassword());
+	pageContext.setAttribute(var, ds, scope);
+	return SKIP_BODY;
+    }
+
+
+    //*********************************************************************
+    // Private utility methods
+
+    private String getDriverClassName() {
+	if (driverClassName != null) {
+	    return driverClassName;
+	}
+	ServletContext application = pageContext.getServletContext();
+	return application.getInitParameter(DRIVER_CLASS_NAME);
+    }
+
+    private String getJdbcURL() {
+	if (jdbcURL != null) {
+	    return jdbcURL;
+	}
+	ServletContext application = pageContext.getServletContext();
+	return application.getInitParameter(JDBC_URL);
+    }
+
+    private String getUserName() {
+	if (userName != null) {
+	    return userName;
+	}
+	ServletContext application = pageContext.getServletContext();
+	return application.getInitParameter(USER_NAME);
+    }
+
+    private String getPassword() {
+	ServletContext application = pageContext.getServletContext();
+	return application.getInitParameter(PASSWORD);
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/common/sql/ParamTagSupport.java b/standard/src/org/apache/taglibs/standard/tag/common/sql/ParamTagSupport.java
new file mode 100644
index 0000000..471b389
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/common/sql/ParamTagSupport.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.common.sql;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.JspTagException;
+import javax.servlet.jsp.jstl.sql.SQLExecutionTag;
+import javax.servlet.jsp.tagext.BodyTagSupport;
+
+import org.apache.taglibs.standard.resources.Resources;
+
+
+/**
+ * <p>Tag handler for <Param> in JSTL, used to set
+ * parameter values for a SQL statement.</p>
+ * 
+ * @author Hans Bergsten
+ */
+
+public abstract class ParamTagSupport extends BodyTagSupport {
+    protected Object value;
+
+    //*********************************************************************
+    // Tag logic
+
+    public int doEndTag() throws JspException {
+	SQLExecutionTag parent = (SQLExecutionTag) 
+	    findAncestorWithClass(this, SQLExecutionTag.class);
+	if (parent == null) {
+	    throw new JspTagException(
+                Resources.getMessage("SQL_PARAM_OUTSIDE_PARENT"));
+	}
+
+	Object paramValue = null;
+	if (value != null) {
+	    paramValue = value;
+	}
+	else if (bodyContent != null) {
+	    paramValue = bodyContent.getString().trim();
+	    if (((String) paramValue).trim().length() == 0) {
+		paramValue = null;
+	    }
+	}
+
+	parent.addSQLParameter(paramValue);
+	return EVAL_PAGE;
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/common/sql/QueryTagSupport.java b/standard/src/org/apache/taglibs/standard/tag/common/sql/QueryTagSupport.java
new file mode 100644
index 0000000..e9f5982
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/common/sql/QueryTagSupport.java
@@ -0,0 +1,299 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.common.sql;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.JspTagException;
+import javax.servlet.jsp.PageContext;
+import javax.servlet.jsp.jstl.core.Config;
+import javax.servlet.jsp.jstl.sql.Result;
+import javax.servlet.jsp.jstl.sql.SQLExecutionTag;
+import javax.servlet.jsp.tagext.BodyTagSupport;
+import javax.servlet.jsp.tagext.TryCatchFinally;
+import javax.sql.DataSource;
+
+import org.apache.taglibs.standard.resources.Resources;
+import org.apache.taglibs.standard.tag.common.core.Util;
+
+
+/**
+ * <p>Tag handler for <Query> in JSTL.  
+ * 
+ * @author Hans Bergsten
+ * @author Justyna Horwat
+ */
+
+public abstract class QueryTagSupport extends BodyTagSupport 
+    implements TryCatchFinally, SQLExecutionTag {
+
+    private String var;
+    private int scope;
+
+    /*
+     * The following properties take expression values, so the
+     * setter methods are implemented by the expression type
+     * specific subclasses.
+     */
+    protected Object rawDataSource;
+    protected boolean dataSourceSpecified;
+    protected String sql;
+    protected int maxRows;
+    protected boolean maxRowsSpecified;
+    protected int startRow;
+
+    /*
+     * Instance variables that are not for attributes
+     */
+    private Connection conn;
+    private List parameters;
+    private boolean isPartOfTransaction;
+
+
+    //*********************************************************************
+    // Constructor and initialization
+
+    public QueryTagSupport() {
+        super();
+        init();
+    }
+
+    private void init() {
+        startRow = 0;
+        maxRows = -1;
+	maxRowsSpecified = dataSourceSpecified = false;
+	isPartOfTransaction = false;
+	conn = null;
+	rawDataSource = null;
+	parameters = null;
+	sql = null;
+	var = null;
+        scope = PageContext.PAGE_SCOPE;
+    }
+
+
+    //*********************************************************************
+    // Accessor methods
+
+    /**
+     * Setter method for the name of the variable to hold the
+     * result.
+     */
+    public void setVar(String var) {
+	this.var = var;
+    }
+
+    /**
+     * Setter method for the scope of the variable to hold the
+     * result.
+     */
+    public void setScope(String scopeName) {
+        scope = Util.getScope(scopeName);
+    }
+
+    //*********************************************************************
+    // Public utility methods
+
+    /**
+     * Called by nested parameter elements to add PreparedStatement
+     * parameter values.
+     */
+    public void addSQLParameter(Object o) {
+	if (parameters == null) {
+	    parameters = new ArrayList();
+	}
+	parameters.add(o);
+    }
+
+    //*********************************************************************
+    // Tag logic
+
+    /**
+     * Prepares for execution by setting the initial state, such as
+     * getting the <code>Connection</code>
+     */
+    public int doStartTag() throws JspException {
+
+        if (!maxRowsSpecified) {
+	    Object obj = Config.find(pageContext, Config.SQL_MAX_ROWS);
+	    if (obj != null) {
+		if (obj instanceof Integer) {
+		    maxRows = ((Integer) obj).intValue();
+		} else if (obj instanceof String) {
+		    try {
+			maxRows = Integer.parseInt((String) obj);
+		    } catch (NumberFormatException nfe) {
+			throw new JspException(
+			    Resources.getMessage("SQL_MAXROWS_PARSE_ERROR",
+						 (String) obj),
+			    nfe);
+		    }
+		} else {
+		    throw new JspException(
+                        Resources.getMessage("SQL_MAXROWS_INVALID"));
+		}
+            }
+        }
+
+	try {
+	    conn = getConnection();
+	} catch (SQLException e) {
+	    throw new JspException(sql + ": " + e.getMessage(), e);
+	}
+
+	return EVAL_BODY_BUFFERED;
+    }
+
+    /**
+     * <p>Execute the SQL statement, set either through the <code>sql</code>
+     * attribute or as the body, and save the result as a variable
+     * named by the <code>var</code> attribute in the scope specified
+     * by the <code>scope</code> attribute, as an object that implements
+     * the Result interface.
+     *
+     * <p>The connection used to execute the statement comes either
+     * from the <code>DataSource</code> specified by the
+     * <code>dataSource</code> attribute, provided by a parent action
+     * element, or is retrieved from a JSP scope  attribute
+     * named <code>javax.servlet.jstl.sql.dataSource</code>.
+     */
+    public int doEndTag() throws JspException {
+	/*
+	 * Use the SQL statement specified by the sql attribute, if any,
+	 * otherwise use the body as the statement.
+	 */
+	String sqlStatement = null;
+	if (sql != null) {
+	    sqlStatement = sql;
+	}
+	else if (bodyContent != null) {
+	    sqlStatement = bodyContent.getString();
+	}
+	if (sqlStatement == null || sqlStatement.trim().length() == 0) {
+	    throw new JspTagException(
+                Resources.getMessage("SQL_NO_STATEMENT"));
+	}
+        /*
+         * We shouldn't have a negative startRow or illegal maxrows
+         */
+        if ((startRow < 0) || (maxRows < -1)) {
+            throw new JspException(
+                Resources.getMessage("PARAM_BAD_VALUE"));
+        }
+
+	Result result = null;
+	/* 
+	 * Note! We must not use the setMaxRows() method on the
+	 * the statement to limit the number of rows, since the
+	 * Result factory must be able to figure out the correct
+	 * value for isLimitedByMaxRows(); there's no way to check
+	 * if it was from the ResultSet.
+          */
+	try {
+	    PreparedStatement ps = conn.prepareStatement(sqlStatement);
+	    setParameters(ps, parameters);
+	    ResultSet rs = ps.executeQuery();
+	    result = new ResultImpl(rs, startRow, maxRows);
+            ps.close();
+	}
+	catch (Throwable e) {
+	    throw new JspException(sqlStatement + ": " + e.getMessage(), e);
+	}
+	pageContext.setAttribute(var, result, scope);
+	return EVAL_PAGE;
+    }
+
+    /**
+     * Just rethrows the Throwable.
+     */
+    public void doCatch(Throwable t) throws Throwable {
+	throw t;
+    }
+
+    /**
+     * Close the <code>Connection</code>, unless this action is used
+     * as part of a transaction.
+     */
+    public void doFinally() {
+	if (conn != null && !isPartOfTransaction) {
+	    try {
+		conn.close();
+	    } catch (SQLException e) {} // Not much we can do
+	}
+
+	conn = null;
+	parameters = null;
+    }
+
+
+    //*********************************************************************
+    // Private utility methods
+
+    private Connection getConnection() throws JspException, SQLException {
+	// Fix: Add all other mechanisms
+	Connection conn = null;
+	isPartOfTransaction = false;
+
+	TransactionTagSupport parent = (TransactionTagSupport) 
+	    findAncestorWithClass(this, TransactionTagSupport.class);
+	if (parent != null) {
+            if (dataSourceSpecified) {
+                throw new JspTagException(
+                    Resources.getMessage("ERROR_NESTED_DATASOURCE"));
+            }
+	    conn = parent.getSharedConnection();
+            isPartOfTransaction = true;
+	} else {
+	    if ((rawDataSource == null) && dataSourceSpecified) {
+		throw new JspException(
+		    Resources.getMessage("SQL_DATASOURCE_NULL"));
+	    }
+	    DataSource dataSource = DataSourceUtil.getDataSource(rawDataSource,
+								 pageContext);
+            try {
+	        conn = dataSource.getConnection();
+            } catch (Exception ex) {
+                throw new JspException(
+                    Resources.getMessage("DATASOURCE_INVALID", 
+                                         ex.toString()));
+            }
+	}
+
+	return conn;
+    }
+
+    private void setParameters(PreparedStatement ps, List parameters) 
+        throws SQLException
+    {
+	if (parameters != null) {
+	    for (int i = 0; i < parameters.size(); i++) {
+                /* The first parameter has index 1.  If a null
+                 * is passed to setObject the parameter will be
+                 * set to JDBC null so an explicit call to
+                 * ps.setNull is not required.
+                 */
+		ps.setObject(i + 1, parameters.get(i));
+	    }
+	}
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/common/sql/ResultImpl.java b/standard/src/org/apache/taglibs/standard/tag/common/sql/ResultImpl.java
new file mode 100644
index 0000000..1b586d8
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/common/sql/ResultImpl.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.common.sql;
+
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import javax.servlet.jsp.jstl.sql.Result;
+
+/**
+ * <p>This class creates a cached version of a <tt>ResultSet</tt>.
+ * It's represented as a <tt>Result</tt> implementation, capable of 
+ * returing an array of <tt>Row</tt> objects containing a <tt>Column</tt> 
+ * instance for each column in the row.</p>
+ *
+ * <p>Note -- this is a private copy for the RI to avoid making the
+ * corresponding class in javax.servlet.* public.</p>
+ *
+ * @author Hans Bergsten
+ * @author Justyna Horwat
+ */
+
+public class ResultImpl implements Result {
+    private List rowMap;
+    private List rowByIndex;
+    private String[] columnNames;
+    private boolean isLimited;
+
+    /**
+     * This constructor reads the ResultSet and saves a cached
+     * copy.
+     *
+     * @param rs an open <tt>ResultSet</tt>, positioned before the first
+     * row
+     * @param startRow, beginning row to be cached
+     * @param maxRows, query maximum rows limit
+     * @exception if a database error occurs
+     */
+    public ResultImpl(ResultSet rs, int startRow, int maxRows)
+        throws SQLException 
+    {
+        rowMap = new ArrayList();
+        rowByIndex = new ArrayList();
+
+        ResultSetMetaData rsmd = rs.getMetaData();
+        int noOfColumns = rsmd.getColumnCount();
+
+        // Create the column name array
+        columnNames = new String[noOfColumns];
+        for (int i = 1; i <= noOfColumns; i++) {
+            columnNames[i-1] = rsmd.getColumnName(i);
+        }
+
+        // Throw away all rows upto startRow
+        for (int i = 0; i < startRow; i++) {
+            rs.next();
+        }
+
+        // Process the remaining rows upto maxRows
+        int processedRows = 0;
+        while (rs.next()) {
+            if ((maxRows != -1) && (processedRows == maxRows)) {
+                isLimited = true; 
+                break;
+            }
+            Object[] columns = new Object[noOfColumns];
+            SortedMap columnMap = 
+                new TreeMap(String.CASE_INSENSITIVE_ORDER);
+
+            // JDBC uses 1 as the lowest index!
+            for (int i = 1; i <= noOfColumns; i++) {
+                Object value =  rs.getObject(i);
+                if (rs.wasNull()) {
+                    value = null;
+                }
+                columns[i-1] = value;
+                columnMap.put(columnNames[i-1], value);
+            }
+            rowMap.add(columnMap);
+            rowByIndex.add(columns);
+            processedRows++;
+        }
+    }
+
+    /**
+     * Returns an array of SortedMap objects. The SortedMap
+     * object key is the ColumnName and the value is the ColumnValue.
+     * SortedMap was created using the CASE_INSENSITIVE_ORDER
+     * Comparator so the key is the case insensitive representation
+     * of the ColumnName.
+     *
+     * @return an array of Map, or null if there are no rows
+     */
+    public SortedMap[] getRows() {
+        if (rowMap == null) {
+            return null;
+        }
+
+        //should just be able to return SortedMap[] object
+        return (SortedMap []) rowMap.toArray(new SortedMap[0]);
+    }
+
+
+    /**
+     * Returns an array of Object[] objects. The first index
+     * designates the Row, the second the Column. The array
+     * stores the value at the specified row and column.
+     *
+     * @return an array of Object[], or null if there are no rows
+     */
+    public Object[][] getRowsByIndex() {
+        if (rowByIndex == null) {
+            return null;
+        }
+
+        //should just be able to return Object[][] object
+        return (Object [][])rowByIndex.toArray(new Object[0][0]);
+    }
+
+    /**
+     * Returns an array of String objects. The array represents
+     * the names of the columns arranged in the same order as in
+     * the getRowsByIndex() method.
+     *
+     * @return an array of String[]
+     */
+    public String[] getColumnNames() {
+        return columnNames;
+    }
+
+    /**
+     * Returns the number of rows in the cached ResultSet
+     *
+     * @return the number of cached rows, or -1 if the Result could
+     *    not be initialized due to SQLExceptions
+     */
+    public int getRowCount() {
+        if (rowMap == null) {
+            return -1;
+        }
+        return rowMap.size();
+    }
+
+    /**
+     * Returns true of the query was limited by a maximum row setting
+     *
+     * @return true if the query was limited by a MaxRows attribute
+     */
+    public boolean isLimitedByMaxRows() {
+        return isLimited;
+    }
+
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/common/sql/SetDataSourceTagSupport.java b/standard/src/org/apache/taglibs/standard/tag/common/sql/SetDataSourceTagSupport.java
new file mode 100644
index 0000000..7710510
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/common/sql/SetDataSourceTagSupport.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.common.sql;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.JspTagException;
+import javax.servlet.jsp.PageContext;
+import javax.servlet.jsp.jstl.core.Config;
+import javax.servlet.jsp.tagext.TagSupport;
+import javax.sql.DataSource;
+
+import org.apache.taglibs.standard.resources.Resources;
+import org.apache.taglibs.standard.tag.common.core.Util;
+
+
+/**
+ * <p>Tag handler for <SetDataSource> in JSTL, used to create
+ * a simple DataSource for prototyping.</p>
+ * 
+ * @author Hans Bergsten
+ * @author Justyna Horwat
+ */
+public class SetDataSourceTagSupport extends TagSupport {
+
+    protected Object dataSource;
+    protected boolean dataSourceSpecified;
+    protected String jdbcURL;
+    protected String driverClassName;
+    protected String userName;
+    protected String password;
+
+    private int scope;
+    private String var;
+
+
+    //*********************************************************************
+    // Constructor and initialization
+
+    public SetDataSourceTagSupport() {
+	super();
+	init();
+    }
+
+    private void init() {
+	dataSource = null;
+	dataSourceSpecified = false;
+	jdbcURL = driverClassName = userName = password = null;
+	var = null;
+	scope = PageContext.PAGE_SCOPE;
+    }
+
+
+    //*********************************************************************
+    // Accessor methods
+
+    /**
+     * Setter method for the scope of the variable to hold the
+     * result.
+     *
+     */
+    public void setScope(String scope) {
+        this.scope = Util.getScope(scope);
+    }
+
+    public void setVar(String var) {
+	this.var = var;
+    }
+
+
+    //*********************************************************************
+    // Tag logic
+
+    public int doStartTag() throws JspException {
+        DataSource ds;
+
+        if (dataSource != null) {
+            ds = DataSourceUtil.getDataSource(dataSource, pageContext);
+        } else {
+	    if (dataSourceSpecified) {
+		throw new JspException(
+                    Resources.getMessage("SQL_DATASOURCE_NULL"));
+	    }
+
+            DataSourceWrapper dsw = new DataSourceWrapper();
+            try {
+                // set driver class iff provided by the tag
+                if (driverClassName != null) {
+                    dsw.setDriverClassName(driverClassName);
+                }
+            }
+            catch (Exception e) {
+                throw new JspTagException(
+                    Resources.getMessage("DRIVER_INVALID_CLASS",
+					 e.toString()), e);
+            }
+            dsw.setJdbcURL(jdbcURL);
+            dsw.setUserName(userName);
+            dsw.setPassword(password);
+	    ds = (DataSource) dsw;
+        }
+
+        if (var != null) {
+	    pageContext.setAttribute(var, ds, scope);
+        } else {
+            Config.set(pageContext, Config.SQL_DATA_SOURCE, ds, scope);
+        }
+
+	return SKIP_BODY;
+    }
+
+    // Releases any resources we may have (or inherit)
+    public void release() {
+	init();
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/common/sql/TransactionTagSupport.java b/standard/src/org/apache/taglibs/standard/tag/common/sql/TransactionTagSupport.java
new file mode 100644
index 0000000..9015dd0
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/common/sql/TransactionTagSupport.java
@@ -0,0 +1,206 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.common.sql;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.JspTagException;
+import javax.servlet.jsp.tagext.TagSupport;
+import javax.servlet.jsp.tagext.TryCatchFinally;
+import javax.sql.DataSource;
+
+import org.apache.taglibs.standard.resources.Resources;
+
+
+/**
+ * <p>Tag handler for <Transaction> in JSTL.  
+ * 
+ * @author Hans Bergsten
+ */
+
+public abstract class TransactionTagSupport extends TagSupport 
+    implements TryCatchFinally {
+
+    //*********************************************************************
+    // Private constants
+
+    private static final String TRANSACTION_READ_COMMITTED
+	= "read_committed";
+    private static final String TRANSACTION_READ_UNCOMMITTED
+	= "read_uncommitted";
+    private static final String TRANSACTION_REPEATABLE_READ
+	= "repeatable_read";
+    private static final String TRANSACTION_SERIALIZABLE
+	= "serializable";
+
+
+    //*********************************************************************
+    // Protected state
+
+    protected Object rawDataSource;
+    protected boolean dataSourceSpecified;
+
+
+    //*********************************************************************
+    // Private state
+
+    private Connection conn;
+    private int isolation;
+    private int origIsolation;
+
+
+    //*********************************************************************
+    // Constructor and initialization
+
+    public TransactionTagSupport() {
+	super();
+	init();
+    }
+
+    private void init() {
+	conn = null;
+	dataSourceSpecified = false;
+	rawDataSource = null;
+	isolation = Connection.TRANSACTION_NONE;
+    }
+
+
+    //*********************************************************************
+    // Tag logic
+
+    /**
+     * Prepares for execution by setting the initial state, such as
+     * getting the <code>Connection</code> and preparing it for
+     * the transaction.
+     */
+    public int doStartTag() throws JspException {
+
+	if ((rawDataSource == null) && dataSourceSpecified) {
+	    throw new JspException(
+                Resources.getMessage("SQL_DATASOURCE_NULL"));
+	}
+
+        DataSource dataSource = DataSourceUtil.getDataSource(rawDataSource,
+							     pageContext);
+
+	try {
+	    conn = dataSource.getConnection();
+	    origIsolation = conn.getTransactionIsolation();
+	    if (origIsolation == Connection.TRANSACTION_NONE) {
+		throw new JspTagException(
+                    Resources.getMessage("TRANSACTION_NO_SUPPORT"));
+	    }
+	    if ((isolation != Connection.TRANSACTION_NONE)
+		    && (isolation != origIsolation)) {
+		conn.setTransactionIsolation(isolation);
+	    }
+	    conn.setAutoCommit(false);
+	} catch (SQLException e) {
+	    throw new JspTagException(
+                Resources.getMessage("ERROR_GET_CONNECTION",
+				     e.toString()), e);
+	} 
+
+	return EVAL_BODY_INCLUDE;
+    }
+
+    /**
+     * Commits the transaction.
+     */
+    public int doEndTag() throws JspException {
+	try {
+	    conn.commit();
+	} catch (SQLException e) {
+	    throw new JspTagException(
+                Resources.getMessage("TRANSACTION_COMMIT_ERROR",
+				     e.toString()), e);
+	}
+	return EVAL_PAGE;
+    }
+
+    /**
+     * Rollbacks the transaction and rethrows the Throwable.
+     */
+    public void doCatch(Throwable t) throws Throwable {
+	if (conn != null) {
+	    try {
+		conn.rollback();
+	    } catch (SQLException e) {
+		// Ignore to not hide orignal exception
+	    }
+	}
+	throw t;
+    }
+
+    /**
+     * Restores the <code>Connection</code> to its initial state and
+     * closes it.
+     */
+    public void doFinally() {
+	if (conn != null) {
+	    try {
+		if ((isolation != Connection.TRANSACTION_NONE)
+		        && (isolation != origIsolation)) {
+		    conn.setTransactionIsolation(origIsolation);
+		}
+		conn.setAutoCommit(true);
+		conn.close();
+	    } catch (SQLException e) {
+		// Not much we can do
+	    }
+	}
+	conn = null;
+    }
+
+    // Releases any resources we may have (or inherit)
+    public void release() {
+	init();
+    }
+
+
+    //*********************************************************************
+    // Public utility methods
+
+    /**
+     * Setter method for the transaction isolation level.
+     */
+    public void setIsolation(String iso) throws JspTagException {
+
+	if (TRANSACTION_READ_COMMITTED.equals(iso)) {
+	    isolation = Connection.TRANSACTION_READ_COMMITTED;
+	} else if (TRANSACTION_READ_UNCOMMITTED.equals(iso)) {
+	    isolation = Connection.TRANSACTION_READ_UNCOMMITTED;
+	} else if (TRANSACTION_REPEATABLE_READ.equals(iso)) {
+	    isolation = Connection.TRANSACTION_REPEATABLE_READ;
+	} else if (TRANSACTION_SERIALIZABLE.equals(iso)) {
+	    isolation = Connection.TRANSACTION_SERIALIZABLE;
+	} else {
+	    throw new JspTagException(
+                Resources.getMessage("TRANSACTION_INVALID_ISOLATION"));
+	}
+    }
+
+    /**
+     * Called by nested parameter elements to get a reference to
+     * the Connection.
+     */
+    public Connection getSharedConnection() {
+	return conn;
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/common/sql/UpdateTagSupport.java b/standard/src/org/apache/taglibs/standard/tag/common/sql/UpdateTagSupport.java
new file mode 100644
index 0000000..954d6de
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/common/sql/UpdateTagSupport.java
@@ -0,0 +1,258 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.common.sql;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.JspTagException;
+import javax.servlet.jsp.PageContext;
+import javax.servlet.jsp.jstl.sql.SQLExecutionTag;
+import javax.servlet.jsp.tagext.BodyTagSupport;
+import javax.servlet.jsp.tagext.TryCatchFinally;
+import javax.sql.DataSource;
+
+import org.apache.taglibs.standard.resources.Resources;
+import org.apache.taglibs.standard.tag.common.core.Util;
+
+/**
+ * <p>Tag handler for <Update> in JSTL.  
+ * 
+ * @author Hans Bergsten
+ * @author Justyna Horwat
+ */
+
+public abstract class UpdateTagSupport extends BodyTagSupport 
+    implements TryCatchFinally, SQLExecutionTag {
+
+    private String var;
+    private int scope;
+
+    /*
+     * The following properties take expression values, so the
+     * setter methods are implemented by the expression type
+     * specific subclasses.
+     */
+    protected Object rawDataSource;
+    protected boolean dataSourceSpecified;
+    protected String sql;
+
+    /*
+     * Instance variables that are not for attributes
+     */
+    private Connection conn;
+    private List parameters;
+    private boolean isPartOfTransaction;
+
+
+    //*********************************************************************
+    // Constructor and initialization
+
+    public UpdateTagSupport() {
+	super();
+	init();
+    }
+
+    private void init() {
+	rawDataSource = null;
+	sql = null;
+	conn = null;
+	parameters = null;
+	isPartOfTransaction = dataSourceSpecified = false;
+        scope = PageContext.PAGE_SCOPE;
+	var = null;
+    }
+
+
+    //*********************************************************************
+    // Accessor methods
+
+    /**
+     * Setter method for the name of the variable to hold the
+     * result.
+     */
+    public void setVar(String var) {
+	this.var = var;
+    }
+
+    /**
+     * Setter method for the scope of the variable to hold the
+     * result.
+     */
+    public void setScope(String scopeName) {
+        scope = Util.getScope(scopeName);
+    }
+
+
+    //*********************************************************************
+    // Tag logic
+
+    /**
+     * Prepares for execution by setting the initial state, such as
+     * getting the <code>Connection</code>
+     */
+    public int doStartTag() throws JspException {
+
+	try {
+	    conn = getConnection();
+	} catch (SQLException e) {
+	    throw new JspException(sql + ": " + e.getMessage(), e);
+	}
+
+	return EVAL_BODY_BUFFERED;
+    }
+
+    /**
+     * <p>Execute the SQL statement, set either through the <code>sql</code>
+     * attribute or as the body, and save the result as a variable
+     * named by the <code>var</code> attribute in the scope specified
+     * by the <code>scope</code> attribute, as an object that implements
+     * the Result interface.
+     *
+     * <p>The connection used to execute the statement comes either
+     * from the <code>DataSource</code> specified by the
+     * <code>dataSource</code> attribute, provided by a parent action
+     * element, or is retrieved from a JSP scope  attribute
+     * named <code>javax.servlet.jsp.jstl.sql.dataSource</code>.
+     */
+    public int doEndTag() throws JspException {
+	/*
+	 * Use the SQL statement specified by the sql attribute, if any,
+	 * otherwise use the body as the statement.
+	 */
+	String sqlStatement = null;
+	if (sql != null) {
+	    sqlStatement = sql;
+	}
+	else if (bodyContent != null) {
+	    sqlStatement = bodyContent.getString();
+	}
+	if (sqlStatement == null || sqlStatement.trim().length() == 0) {
+	    throw new JspTagException(
+                Resources.getMessage("SQL_NO_STATEMENT"));
+	}
+
+	int result = 0;
+	try {
+	    PreparedStatement ps = conn.prepareStatement(sqlStatement);
+	    setParameters(ps, parameters);
+	    result = ps.executeUpdate();
+            ps.close();
+	}
+	catch (Throwable e) {
+	    throw new JspException(sqlStatement + ": " + e.getMessage(), e);
+	}
+	if (var != null)
+	    pageContext.setAttribute(var, new Integer(result), scope);
+	return EVAL_PAGE;
+    }
+
+    /**
+     * Just rethrows the Throwable.
+     */
+    public void doCatch(Throwable t) throws Throwable {
+	throw t;
+    }
+
+    /**
+     * Close the <code>Connection</code>, unless this action is used
+     * as part of a transaction.
+     */
+    public void doFinally() {
+	if (conn != null && !isPartOfTransaction) {
+	    try {
+		conn.close();
+	    } catch (SQLException e) {
+		// Not much we can do
+	    }
+	}
+
+	parameters = null;
+	conn = null;
+    }
+
+
+    //*********************************************************************
+    // Public utility methods
+
+    /**
+     * Called by nested parameter elements to add PreparedStatement
+     * parameter values.
+     */
+    public void addSQLParameter(Object o) {
+	if (parameters == null) {
+	    parameters = new ArrayList();
+	}
+	parameters.add(o);
+    }
+
+
+    //*********************************************************************
+    // Private utility methods
+
+    private Connection getConnection() throws JspException, SQLException {
+	// Fix: Add all other mechanisms
+	Connection conn = null;
+	isPartOfTransaction = false;
+
+	TransactionTagSupport parent = (TransactionTagSupport) 
+	    findAncestorWithClass(this, TransactionTagSupport.class);
+	if (parent != null) {
+            if (dataSourceSpecified) {
+                throw new JspTagException(
+                    Resources.getMessage("ERROR_NESTED_DATASOURCE"));
+            }
+	    conn = parent.getSharedConnection();
+            isPartOfTransaction = true;
+	} else {
+	    if ((rawDataSource == null) && dataSourceSpecified) {
+		throw new JspException(
+		    Resources.getMessage("SQL_DATASOURCE_NULL"));
+	    }
+	    DataSource dataSource = DataSourceUtil.getDataSource(rawDataSource,
+								 pageContext);
+            try {
+                conn = dataSource.getConnection();
+            } catch (Exception ex) {
+                throw new JspException(
+                    Resources.getMessage("DATASOURCE_INVALID",
+					 ex.toString()));
+            }
+	}
+
+	return conn;
+    }
+
+    private void setParameters(PreparedStatement ps, List parameters) 
+        throws SQLException
+    {
+	if (parameters != null) {
+	    for (int i = 0; i < parameters.size(); i++) {
+                /* The first parameter has index 1.  If a null
+                 * is passed to setObject the parameter will be
+                 * set to JDBC null so an explicit call to
+                 * ps.setNull is not required.
+                 */
+                ps.setObject(i + 1, parameters.get(i));
+	    }
+	}
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/common/xml/ExprSupport.java b/standard/src/org/apache/taglibs/standard/tag/common/xml/ExprSupport.java
new file mode 100644
index 0000000..fb5af3a
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/common/xml/ExprSupport.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.common.xml;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.JspTagException;
+import javax.servlet.jsp.tagext.TagSupport;
+
+/**
+ * <p>Tag handler for <expr> in JSTL's XML library.</p>
+ *
+ * @author Shawn Bayern
+ */
+
+public abstract class ExprSupport extends TagSupport {
+
+    //*********************************************************************
+    // Internal state
+
+    private String select;                       // tag attribute
+    protected boolean escapeXml;		 // tag attribute
+
+    //*********************************************************************
+    // Construction and initialization
+
+    /**
+     * Constructs a new handler.  As with TagSupport, subclasses should
+     * not provide other constructors and are expected to call the
+     * superclass constructor.
+     */
+    public ExprSupport() {
+        super();
+        init();
+    }
+
+    // resets local state
+    private void init() {
+	select = null;
+        escapeXml = true;
+    }
+
+
+    //*********************************************************************
+    // Tag logic
+
+    // applies XPath expression from 'select' and prints the result
+    public int doStartTag() throws JspException {
+        try {
+	    XPathUtil xu = new XPathUtil(pageContext);
+	    String result = xu.valueOf(XPathUtil.getContext(this), select);
+	    org.apache.taglibs.standard.tag.common.core.OutSupport.out(
+              pageContext, escapeXml, result);
+	    return SKIP_BODY;
+        } catch (java.io.IOException ex) {
+	    throw new JspTagException(ex.toString(), ex);
+        }
+    }
+
+    // Releases any resources we may have (or inherit)
+    public void release() {
+        super.release();
+        init();
+    }
+
+
+    //*********************************************************************
+    // Attribute accessors
+
+    public void setSelect(String select) {
+	this.select = select;
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/common/xml/ForEachTag.java b/standard/src/org/apache/taglibs/standard/tag/common/xml/ForEachTag.java
new file mode 100644
index 0000000..6264c13
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/common/xml/ForEachTag.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.common.xml;
+
+import java.util.List;
+
+import javax.servlet.jsp.JspTagException;
+import javax.servlet.jsp.jstl.core.LoopTagSupport;
+
+import org.apache.taglibs.standard.resources.Resources;
+
+/**
+ * <p>Support for the XML library's <forEach> tag.</p>
+ *
+ * @see javax.servlet.jsp.jstl.core.LoopTagSupport
+ * @author Shawn Bayern
+ */
+public class ForEachTag extends LoopTagSupport {
+
+    //*********************************************************************
+    // Private state
+
+    private String select;				// tag attribute
+    private List nodes;					// XPath result
+    private int nodesIndex;				// current index
+    private org.w3c.dom.Node current;			// current node
+
+    //*********************************************************************
+    // Iteration control methods
+
+    // (We inherit semantics and Javadoc from LoopTagSupport.) 
+
+    protected void prepare() throws JspTagException {
+        nodesIndex = 0;
+        XPathUtil xu = new XPathUtil(pageContext);
+        nodes = xu.selectNodes(XPathUtil.getContext(this), select);
+    }
+
+    protected boolean hasNext() throws JspTagException {
+        return (nodesIndex < nodes.size());
+    }
+
+    protected Object next() throws JspTagException {
+	Object o = nodes.get(nodesIndex++);
+	if (!(o instanceof org.w3c.dom.Node))
+	    throw new JspTagException(
+		Resources.getMessage("FOREACH_NOT_NODESET"));
+	current = (org.w3c.dom.Node) o;
+        return current;
+    }
+
+
+    //*********************************************************************
+    // Tag logic and lifecycle management
+
+    // Releases any resources we may have (or inherit)
+    public void release() {
+	init();
+        super.release();
+    }
+
+
+    //*********************************************************************
+    // Attribute accessors
+
+    public void setSelect(String select) {
+	this.select = select;
+    }
+
+    public void setBegin(int begin) throws JspTagException {
+        this.beginSpecified = true;
+        this.begin = begin;
+        validateBegin();
+    }
+
+    public void setEnd(int end) throws JspTagException {
+        this.endSpecified = true;
+        this.end = end;
+        validateEnd();
+    }
+
+    public void setStep(int step) throws JspTagException {
+        this.stepSpecified = true;
+        this.step = step;
+        validateStep();
+    }
+    
+    //*********************************************************************
+    // Public methods for subtags
+
+    /* Retrieves the current context. */
+    public org.w3c.dom.Node getContext() throws JspTagException {
+	// expose the current node as the context
+        return current;
+    }
+
+
+    //*********************************************************************
+    // Private utility methods
+
+    private void init() {
+	select = null;
+	nodes = null;
+	nodesIndex = 0;
+	current = null;
+    }	
+}
+
diff --git a/standard/src/org/apache/taglibs/standard/tag/common/xml/IfTag.java b/standard/src/org/apache/taglibs/standard/tag/common/xml/IfTag.java
new file mode 100644
index 0000000..1899edf
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/common/xml/IfTag.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.common.xml;
+
+import javax.servlet.jsp.JspTagException;
+import javax.servlet.jsp.jstl.core.ConditionalTagSupport;
+
+/**
+ * <p>Tag handler for <if> in JSTL's XML library.</p>
+ *
+ * @author Shawn Bayern
+ */
+
+public class IfTag extends ConditionalTagSupport {
+
+    //*********************************************************************
+    // Constructor and lifecycle management
+
+    // initialize inherited and local state
+    public IfTag() {
+        super();
+        init();
+    }
+
+    // Releases any resources we may have (or inherit)
+    public void release() {
+        super.release();
+        init();
+    }
+
+
+    //*********************************************************************
+    // Supplied conditional logic
+
+    protected boolean condition() throws JspTagException {
+        XPathUtil xu = new XPathUtil(pageContext);
+        return (xu.booleanValueOf(XPathUtil.getContext(this), select));
+    }
+
+
+    //*********************************************************************
+    // Private state
+
+    private String select;               // the value of the 'test' attribute
+
+
+    //*********************************************************************
+    // Attribute accessors
+
+    public void setSelect(String select) {
+        this.select = select;
+    }
+
+
+    //*********************************************************************
+    // Private utility methods
+
+    // resets internal state
+    private void init() {
+        select = null;
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/common/xml/JSTLPrefixResolver.java b/standard/src/org/apache/taglibs/standard/tag/common/xml/JSTLPrefixResolver.java
new file mode 100644
index 0000000..846c907
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/common/xml/JSTLPrefixResolver.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.common.xml;
+
+import java.util.HashMap;
+
+import org.apache.xml.utils.PrefixResolver;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+
+/**
+ * <meta name="usage" content="general"/>
+ * This class implements a JSTL PrefixResolver that
+ * can be used to perform prefix-to-namespace lookup
+ * for the XPath object.
+ */
+public class JSTLPrefixResolver implements PrefixResolver
+{
+
+  /**
+   * The context to resolve the prefix from, if the context
+   * is not given. */
+
+    HashMap namespaces;
+
+  /**
+   * The URI for the XML namespace.
+   * (Duplicate of that found in org.apache.xpath.XPathContext). */
+     
+  public static final String S_XMLNAMESPACEURI =
+    "http://www.w3.org/XML/1998/namespace";
+
+  /**
+   * No-arg constructor which would create empty HashMap of namespaces
+   */
+  public JSTLPrefixResolver()
+  {
+    namespaces = new HashMap();
+  }
+
+  public JSTLPrefixResolver( HashMap nses )
+  {
+    namespaces = nses;
+  }
+
+  /**
+   * Given a namespace, get the corresponding prefix.  This assumes that
+   * the PrevixResolver hold's it's own namespace context, or is a namespace
+   * context itself.
+   * @param prefix Prefix to resolve.
+   * @return Namespace that prefix resolves to, or null if prefix
+   * is not bound.
+   */
+  public String getNamespaceForPrefix(String prefix)
+  {
+    return (String)namespaces.get(prefix);
+  }
+
+  /**
+   * Given a prefix and a Context Node, get the corresponding namespace.
+   * Warning: This will not work correctly if namespaceContext
+   * is an attribute node.
+   * @param prefix Prefix to resolve.
+   * @param namespaceContext Node from which to start searching for a
+   * xmlns attribute that binds a prefix to a namespace.
+   * @return Namespace that prefix resolves to, or null if prefix
+   * is not bound.
+   */
+  public String getNamespaceForPrefix(String prefix,
+                                      org.w3c.dom.Node namespaceContext)
+  {
+
+    Node parent = namespaceContext;
+    String namespace = null;
+
+    if (prefix.equals("xml"))
+    {
+      namespace = S_XMLNAMESPACEURI;
+    }
+    else
+    {
+      int type;
+
+      while ((null != parent) && (null == namespace)
+             && (((type = parent.getNodeType()) == Node.ELEMENT_NODE)
+                 || (type == Node.ENTITY_REFERENCE_NODE)))
+      {
+        if (type == Node.ELEMENT_NODE)
+        {
+          NamedNodeMap nnm = parent.getAttributes();
+
+          for (int i = 0; i < nnm.getLength(); i++)
+          {
+            Node attr = nnm.item(i);
+            String aname = attr.getNodeName();
+            boolean isPrefix = aname.startsWith("xmlns:");
+
+            if (isPrefix || aname.equals("xmlns"))
+            {
+              int index = aname.indexOf(':');
+              String p = isPrefix ? aname.substring(index + 1) : "";
+
+              if (p.equals(prefix))
+              {
+                namespace = attr.getNodeValue();
+
+                break;
+              }
+            }
+          }
+        }
+
+        parent = parent.getParentNode();
+      }
+    }
+
+    return namespace;
+  }
+
+  /**
+   * Return the base identifier.
+   *
+   * @return null
+   */
+  public String getBaseIdentifier()
+  {
+    return null;
+  }
+
+  /**
+   * @see PrefixResolver#handlesNullPrefixes() */
+  public boolean handlesNullPrefixes() {
+    return false;
+  }
+
+  public void addNamespace ( String prefix, String uri ) {
+    namespaces.put( prefix, uri );
+  }
+
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/common/xml/JSTLXPathAPI.java b/standard/src/org/apache/taglibs/standard/tag/common/xml/JSTLXPathAPI.java
new file mode 100644
index 0000000..7f70007
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/common/xml/JSTLXPathAPI.java
@@ -0,0 +1,303 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.common.xml;
+
+import java.util.Vector;
+
+import javax.servlet.jsp.JspTagException;
+import javax.xml.transform.TransformerException;
+
+import org.apache.taglibs.standard.resources.Resources;
+import org.apache.xml.utils.PrefixResolver;
+import org.apache.xpath.XPath;
+import org.apache.xpath.XPathAPI;
+import org.apache.xpath.XPathContext;
+import org.apache.xpath.objects.XObject;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.traversal.NodeIterator;
+
+/**
+ * The methods in this class are convenience methods into the
+ * low-level XPath API.
+ * These functions tend to be a little slow, since a number of objects must be
+ * created for each evaluation.  A faster way is to precompile the
+ * XPaths using the low-level API, and then just use the XPaths
+ * over and over.
+ *
+ * NOTE: In particular, each call to this method will create a new
+ * XPathContext, a new DTMManager... and thus a new DTM. That's very
+ * safe, since it guarantees that you're always processing against a
+ * fully up-to-date view of your document. But it's also portentially
+ * very expensive, since you're rebuilding the DTM every time. You should
+ * consider using an instance of CachedXPathAPI rather than these static
+ * methods.
+ *
+ * @see <a href="http://www.w3.org/TR/xpath">XPath Specification</a>
+ * 
+ */
+public class JSTLXPathAPI extends XPathAPI {    
+    /**
+     * Use an XPath string to select a single node.
+     * XPath namespace prefixes are resolved using the prefixResolver.
+     *
+     * @param contextNode The node to start searching from.
+     * @param str A valid XPath string.
+     * @param prefixResolver The PrefixResolver using which prefixes in the XPath will be resolved to namespaces.
+     * @return The first node found that matches the XPath, or null.
+     *
+     * @throws JspTagException
+     */
+    public static Node selectSingleNode(
+    Node contextNode, String str, PrefixResolver prefixResolver)
+    throws JspTagException {
+        
+        // Have the XObject return its result as a NodeSetDTM.
+        NodeIterator nl = selectNodeIterator(contextNode, str, prefixResolver);
+        
+        // Return the first node, or null
+        return nl.nextNode();
+    }
+    
+    /**
+     * Use an XPath string to select a single node.
+     * XPath namespace prefixes are resolved using the prefixResolver.
+     *
+     * @param contextNode The node to start searching from.
+     * @param str A valid XPath string.
+     * @param prefixResolver The PrefixResolver using which prefixes in the XPath will be resolved to namespaces.
+     * @return The first node found that matches the XPath, or null.
+     *
+     * @throws JspTagException
+     */
+    public static Node selectSingleNode(
+    Node contextNode, String str, PrefixResolver prefixResolver,
+    XPathContext xpathSupport ) throws JspTagException {
+        
+        // Have the XObject return its result as a NodeSetDTM.
+        NodeIterator nl = selectNodeIterator(contextNode, str, prefixResolver, xpathSupport);
+        
+        // Return the first node, or null
+        return nl.nextNode();
+    }
+    
+    /**
+     *  Use an XPath string to select a nodelist.
+     *  XPath namespace prefixes are resolved using PrefixResolver.
+     *
+     *  @param contextNode The node to start searching from.
+     *  @param str A valid XPath string.
+     *  @param prefixResolver The PrefixResolver using which prefixes in the XPath will be resolved to namespaces.
+     *  @return A NodeIterator, should never be null.
+     *
+     * @throws JspTagException
+     */
+    public static NodeIterator selectNodeIterator(
+    Node contextNode, String str, PrefixResolver prefixResolver)
+    throws JspTagException {
+        
+        // Execute the XPath, and have it return the result
+        XObject list = eval(contextNode, str, prefixResolver, null);
+        
+        // Have the XObject return its result as a NodeSetDTM.
+        return getNodeIterator(list);
+    }
+    
+    /**
+     *  Use an XPath string to select a nodelist.
+     *  XPath namespace prefixes are resolved using PrefixResolver.
+     *
+     *  @param contextNode The node to start searching from.
+     *  @param str A valid XPath string.
+     *  @param prefixResolver The PrefixResolver using which prefixes in the XPath will be resolved to namespaces.
+     *  @return A NodeIterator, should never be null.
+     *
+     * @throws JspTagException
+     */
+    public static NodeIterator selectNodeIterator(
+    Node contextNode, String str, PrefixResolver prefixResolver,
+    XPathContext xpathSupport ) throws JspTagException {
+        
+        // Execute the XPath, and have it return the result
+        XObject list = eval(contextNode, str, prefixResolver, xpathSupport);
+        
+        // Have the XObject return its result as a NodeSetDTM.
+        return getNodeIterator(list);
+    }
+    
+    /**
+     *  Use an XPath string to select a nodelist.
+     *  XPath namespace prefixes are resolved using the prefixResolver.
+     *
+     *  @param contextNode The node to start searching from.
+     *  @param str A valid XPath string.
+     *  @param prefixResolver The PrefixResolver using which prefixes in the XPath will be resolved to namespaces.
+     *  @return A NodeIterator, should never be null.
+     *
+     * @throws JspTagException
+     */
+    private static NodeList selectNodeList(
+    Node contextNode, String str, PrefixResolver prefixResolver)
+    throws JspTagException {
+        // Execute the XPath, and have it return the result
+        XObject list = eval(contextNode, str, prefixResolver, null);
+        
+        // Return a NodeList.
+        return getNodeList(list);
+    }
+    
+    /**
+     *  Use an XPath string to select a nodelist.
+     *  XPath namespace prefixes are resolved using the prefixResolver.
+     *
+     *  @param contextNode The node to start searching from.
+     *  @param str A valid XPath string.
+     *  @param prefixResolver The PrefixResolver using which prefixes in the XPath will be resolved to namespaces.
+     *  @return A NodeIterator, should never be null.
+     *
+     * @throws JspTagException
+     */
+    public static NodeList selectNodeList(
+    Node contextNode, String str, PrefixResolver prefixResolver,
+    XPathContext xpathSupport ) 
+    throws JspTagException 
+    {        
+        // Execute the XPath, and have it return the result
+        XObject list = eval(contextNode, str, prefixResolver, xpathSupport);
+        
+        // Return a NodeList.
+        return getNodeList(list);
+    }
+        
+    /**
+     * Returns a NodeIterator from an XObject.
+     *  @param list The XObject from which a NodeIterator is returned.
+     *  @return A NodeIterator, should never be null.
+     *  @throws JspTagException
+     */
+    private static NodeIterator getNodeIterator(XObject list) 
+    throws JspTagException {
+        try {
+            return list.nodeset();
+        } catch (TransformerException ex) {
+            throw new JspTagException(
+                Resources.getMessage("XPATH_ERROR_XOBJECT", ex.toString()), ex);            
+        }
+    }        
+
+    /**
+     * Returns a NodeList from an XObject.
+     *  @param list The XObject from which a NodeList is returned.
+     *  @return A NodeList, should never be null.
+     *  @throws JspTagException
+     */
+    static NodeList getNodeList(XObject list) 
+    throws JspTagException {
+        try {
+            return list.nodelist();
+        } catch (TransformerException ex) {
+            throw new JspTagException(
+                Resources.getMessage("XPATH_ERROR_XOBJECT", ex.toString()), ex);            
+        }
+    }        
+    
+    /**
+     *   Evaluate XPath string to an XObject.
+     *   XPath namespace prefixes are resolved from the namespaceNode.
+     *   The implementation of this is a little slow, since it creates
+     *   a number of objects each time it is called.  This could be optimized
+     *   to keep the same objects around, but then thread-safety issues would arise.
+     *
+     *   @param contextNode The node to start searching from.
+     *   @param str A valid XPath string.
+     *   @param namespaceNode The node from which prefixes in the XPath will be resolved to namespaces.
+     *   @param prefixResolver Will be called if the parser encounters namespace
+     *                         prefixes, to resolve the prefixes to URLs.
+     *   @return An XObject, which can be used to obtain a string, number, nodelist, etc, should never be null.
+     *   @see org.apache.xpath.objects.XObject
+     *   @see org.apache.xpath.objects.XNull
+     *   @see org.apache.xpath.objects.XBoolean
+     *   @see org.apache.xpath.objects.XNumber
+     *   @see org.apache.xpath.objects.XString
+     *   @see org.apache.xpath.objects.XRTreeFrag
+     *
+     * @throws JspTagException
+     */
+    public static XObject eval(
+    Node contextNode, String str, PrefixResolver prefixResolver,
+    XPathContext xpathSupport) throws JspTagException {
+        //System.out.println("eval of XPathContext params: contextNode:str(xpath)"+
+        // ":prefixResolver:xpathSupport => " + contextNode + ":" + str + ":" +
+        //  prefixResolver + ":" + xpathSupport );        
+        try {
+            if (xpathSupport == null) {
+                return eval(contextNode, str, prefixResolver);
+            }
+            
+            // Since we don't have a XML Parser involved here, install some default support
+            // for things like namespaces, etc.
+            // (Changed from: XPathContext xpathSupport = new XPathContext();
+            //    because XPathContext is weak in a number of areas... perhaps
+            //    XPathContext should be done away with.)
+            // Create the XPath object.
+            XPath xpath = new XPath(str, null, prefixResolver, XPath.SELECT, null);
+            
+            // Execute the XPath, and have it return the result
+            int ctxtNode = xpathSupport.getDTMHandleFromNode(contextNode);
+            
+            // System.out.println("Context Node id ( after getDTMHandlerFromNode) => " + ctxtNode );
+            XObject xobj = xpath.execute(xpathSupport, ctxtNode, prefixResolver);
+            return xobj;
+        } catch (TransformerException ex) {
+            throw new JspTagException(
+                Resources.getMessage("XPATH_ERROR_EVALUATING_EXPR", str, ex.toString()), ex);            
+        } catch (IllegalArgumentException ex) {
+            throw new JspTagException(
+                Resources.getMessage("XPATH_ILLEGAL_ARG_EVALUATING_EXPR", str, ex.toString()), ex);            
+        }
+    }
+    
+    public static XObject eval(
+    Node contextNode, String str, PrefixResolver prefixResolver,
+    XPathContext xpathSupport, Vector varQNames) throws JspTagException {
+        //p("***************** eval ");
+        //p( "contextNode => " + contextNode );
+        //p( "XPath str => " + str );
+        //p( "PrefixResolver => " + prefixResolver );
+        //p( "XPath Context => " + xpathSupport );
+        //p( "Var QNames => " + varQNames );
+        //p( "Global Var Size => " + varQNames.size() );        
+        try {
+            XPath xpath = new XPath(str, null, prefixResolver, XPath.SELECT, null);            
+            xpath.fixupVariables( varQNames, varQNames.size());
+            // Execute the XPath, and have it return the result
+            int ctxtNode = xpathSupport.getDTMHandleFromNode(contextNode);            
+            // System.out.println("Context Node id ( after getDTMHandlerFromNode) => " + ctxtNode );            
+            return xpath.execute(xpathSupport, ctxtNode, prefixResolver);
+        } catch (TransformerException ex) {
+            throw new JspTagException(
+            Resources.getMessage("XPATH_ERROR_EVALUATING_EXPR", str, ex.toString()), ex);
+        } catch (IllegalArgumentException ex) {
+            throw new JspTagException(
+            Resources.getMessage("XPATH_ILLEGAL_ARG_EVALUATING_EXPR", str, ex.toString()), ex);
+        }
+    } 
+    
+    private static void p(String s) {
+        System.out.println("[JSTLXPathAPI] " + s);
+    }    
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/common/xml/ParamSupport.java b/standard/src/org/apache/taglibs/standard/tag/common/xml/ParamSupport.java
new file mode 100644
index 0000000..99d76a7
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/common/xml/ParamSupport.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.common.xml;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.JspTagException;
+import javax.servlet.jsp.tagext.BodyTagSupport;
+import javax.servlet.jsp.tagext.Tag;
+
+import org.apache.taglibs.standard.resources.Resources;
+
+/**
+ * <p>Support for tag handlers for <param>, the XML parameter
+ * subtag for <transformt<.</p>
+ *
+ * @see TransformSupport
+ * @author Shawn Bayern
+ */
+
+public abstract class ParamSupport extends BodyTagSupport {
+
+    //*********************************************************************
+    // Protected state
+
+    protected String name;                       // 'name' attribute
+    protected Object value;                      // 'value' attribute
+
+    //*********************************************************************
+    // Constructor and initialization
+
+    public ParamSupport() {
+	super();
+	init();
+    }
+
+    private void init() {
+	name = null;
+	value = null;
+    }
+
+
+    //*********************************************************************
+    // Tag logic
+
+    // simply send our name and value to our parent <transform> tag
+    public int doEndTag() throws JspException {
+	Tag t = findAncestorWithClass(this, TransformSupport.class);
+	if (t == null)
+	    throw new JspTagException(
+		Resources.getMessage("PARAM_OUTSIDE_TRANSFORM"));
+	TransformSupport parent = (TransformSupport) t;
+
+	Object value = this.value;
+	if (value == null) {
+            if (bodyContent == null || bodyContent.getString() == null)
+                value = "";
+            else
+                value = bodyContent.getString().trim();
+        }
+	parent.addParameter(name, value);
+	return EVAL_PAGE;
+    }
+
+    // Releases any resources we may have (or inherit)
+    public void release() {
+	init();
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/common/xml/ParseSupport.java b/standard/src/org/apache/taglibs/standard/tag/common/xml/ParseSupport.java
new file mode 100644
index 0000000..3bc8a54
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/common/xml/ParseSupport.java
@@ -0,0 +1,314 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.common.xml;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.io.StringReader;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.JspTagException;
+import javax.servlet.jsp.PageContext;
+import javax.servlet.jsp.tagext.BodyTagSupport;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMResult;
+import javax.xml.transform.sax.SAXTransformerFactory;
+import javax.xml.transform.sax.TransformerHandler;
+
+import org.apache.taglibs.standard.resources.Resources;
+import org.apache.taglibs.standard.tag.common.core.ImportSupport;
+import org.apache.taglibs.standard.tag.common.core.Util;
+import org.w3c.dom.Document;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLFilter;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.XMLReaderFactory;
+
+/**
+ * <p>Support for tag handlers for <parse>, the XML parsing tag.</p>
+ *
+ * @author Shawn Bayern
+ */
+public abstract class ParseSupport extends BodyTagSupport {
+
+    //*********************************************************************
+    // Protected state
+
+    protected Object xml;                          // 'xml' attribute
+    protected String systemId;                     // 'systemId' attribute
+    protected XMLFilter filter;			   // 'filter' attribute
+
+    //*********************************************************************
+    // Private state
+
+    private String var;                            // 'var' attribute
+    private String varDom;			   // 'varDom' attribute
+    private int scope;				   // processed 'scope' attr
+    private int scopeDom;			   // processed 'scopeDom' attr
+
+    // state in support of XML parsing...
+    private DocumentBuilderFactory dbf;
+    private DocumentBuilder db;
+    private TransformerFactory tf;
+    private TransformerHandler th;
+
+
+    //*********************************************************************
+    // Constructor and initialization
+
+    public ParseSupport() {
+	super();
+	init();
+    }
+
+    private void init() {
+	var = varDom = null;
+	xml = null;
+	systemId = null;
+	filter = null;
+	dbf = null;
+	db = null;
+	tf = null;
+	th = null;
+	scope = PageContext.PAGE_SCOPE;
+	scopeDom = PageContext.PAGE_SCOPE;
+    }
+
+
+    //*********************************************************************
+    // Tag logic
+
+    // parse 'source' or body, storing result in 'var'
+    public int doEndTag() throws JspException {
+      try {
+	
+	// set up our DocumentBuilder
+        if (dbf == null) {
+            dbf = DocumentBuilderFactory.newInstance();
+            dbf.setNamespaceAware(true);
+            dbf.setValidating(false);
+        }
+        db = dbf.newDocumentBuilder();
+
+	// if we've gotten a filter, set up a transformer to support it
+	if (filter != null) {
+            if (tf == null)
+                tf = TransformerFactory.newInstance();
+            if (!tf.getFeature(SAXTransformerFactory.FEATURE))
+                throw new JspTagException(
+		    Resources.getMessage("PARSE_NO_SAXTRANSFORMER"));
+            SAXTransformerFactory stf = (SAXTransformerFactory) tf;
+            th = stf.newTransformerHandler();
+	}
+
+	// produce a Document by parsing whatever the attributes tell us to use
+	Document d;
+	Object xmlText = this.xml;
+	if (xmlText == null) {
+	    // if the attribute was specified, use the body as 'xml'
+	    if (bodyContent != null && bodyContent.getString() != null)
+		xmlText = bodyContent.getString().trim();
+	    else
+		xmlText = "";
+	}
+	if (xmlText instanceof String)
+	    d = parseStringWithFilter((String) xmlText, filter);
+	else if (xmlText instanceof Reader)
+	    d = parseReaderWithFilter((Reader) xmlText, filter);
+	else
+	    throw new JspTagException(
+	        Resources.getMessage("PARSE_INVALID_SOURCE"));
+
+	// we've got a Document object; store it out as appropriate
+	// (let any exclusivity or other constraints be enforced by TEI/TLV)
+	if (var != null)
+	    pageContext.setAttribute(var, d, scope);
+	if (varDom != null)
+	    pageContext.setAttribute(varDom, d, scopeDom);
+
+	return EVAL_PAGE;
+      } catch (SAXException ex) {
+	throw new JspException(ex);
+      } catch (IOException ex) {
+	throw new JspException(ex);
+      } catch (ParserConfigurationException ex) {
+	throw new JspException(ex);
+      } catch (TransformerConfigurationException ex) {
+	throw new JspException(ex);
+      }
+    }
+
+    // Releases any resources we may have (or inherit)
+    public void release() {
+	init();
+    }
+
+
+    //*********************************************************************
+    // Private utility methods
+
+    /** Parses the given InputSource after, applying the given XMLFilter. */
+    private Document parseInputSourceWithFilter(InputSource s, XMLFilter f)
+            throws SAXException, IOException {
+	if (f != null) {
+            // prepare an output Document
+            Document o = db.newDocument();
+
+            // use TrAX to adapt SAX events to a Document object
+            th.setResult(new DOMResult(o));
+            XMLReader xr = XMLReaderFactory.createXMLReader();
+	    xr.setEntityResolver(new JstlEntityResolver(pageContext));
+            //   (note that we overwrite the filter's parent.  this seems
+            //    to be expected usage.  we could cache and reset the old
+            //    parent, but you can't setParent(null), so this wouldn't
+            //    be perfect.)
+            f.setParent(xr);
+            f.setContentHandler(th);
+            f.parse(s);
+            return o;
+	} else
+	    return parseInputSource(s);	
+    }
+
+    /** Parses the given Reader after applying the given XMLFilter. */
+    private Document parseReaderWithFilter(Reader r, XMLFilter f)
+            throws SAXException, IOException {
+	return parseInputSourceWithFilter(new InputSource(r), f);
+    }
+
+    /** Parses the given String after applying the given XMLFilter. */
+    private Document parseStringWithFilter(String s, XMLFilter f)
+            throws SAXException, IOException {
+        StringReader r = new StringReader(s);
+        return parseReaderWithFilter(r, f);
+    }
+
+    /** Parses the given Reader after applying the given XMLFilter. */
+    private Document parseURLWithFilter(String url, XMLFilter f)
+            throws SAXException, IOException {
+	return parseInputSourceWithFilter(new InputSource(url), f);
+    }
+
+    /** Parses the given InputSource into a Document. */
+    private Document parseInputSource(InputSource s)
+	    throws SAXException, IOException {
+	db.setEntityResolver(new JstlEntityResolver(pageContext));
+
+        // normalize URIs so they can be processed consistently by resolver
+        if (systemId == null)
+            s.setSystemId("jstl:");
+	else if (ImportSupport.isAbsoluteUrl(systemId))
+            s.setSystemId(systemId);
+        else
+            s.setSystemId("jstl:" + systemId);
+	return db.parse(s);
+    }
+
+    /** Parses the given Reader into a Document. */
+    private Document parseReader(Reader r) throws SAXException, IOException {
+        return parseInputSource(new InputSource(r));
+    }
+
+    /** Parses the given String into a Document. */
+    private Document parseString(String s) throws SAXException, IOException {
+        StringReader r = new StringReader(s);
+        return parseReader(r);
+    }
+
+    /** Parses the URL (passed as a String) into a Document. */
+    private Document parseURL(String url) throws SAXException, IOException {
+	return parseInputSource(new InputSource(url));
+    }
+
+    //*********************************************************************
+    // JSTL-specific EntityResolver class
+
+    /** Lets us resolve relative external entities. */
+    public static class JstlEntityResolver implements EntityResolver {
+	private final PageContext ctx;
+        public JstlEntityResolver(PageContext ctx) {
+            this.ctx = ctx;
+        }
+        public InputSource resolveEntity(String publicId, String systemId)
+	        throws FileNotFoundException {
+
+	    // pass if we don't have a systemId
+	    if (systemId == null)
+		return null;
+
+	    // strip leading "jstl:" off URL if applicable
+	    if (systemId.startsWith("jstl:"))
+		systemId = systemId.substring(5);
+
+	    // we're only concerned with relative URLs
+	    if (ImportSupport.isAbsoluteUrl(systemId))
+		return null;
+
+	    // for relative URLs, load and wrap the resource.
+	    // don't bother checking for 'null' since we specifically want
+	    // the parser to fail if the resource doesn't exist
+	    InputStream s;
+	    if (systemId.startsWith("/")) {
+	        s = ctx.getServletContext().getResourceAsStream(systemId);
+	        if (s == null)
+		    throw new FileNotFoundException(
+			Resources.getMessage("UNABLE_TO_RESOLVE_ENTITY",
+			 systemId));
+	    } else {
+		String pagePath =
+		    ((HttpServletRequest) ctx.getRequest()).getServletPath();
+		String basePath =
+		    pagePath.substring(0, pagePath.lastIndexOf("/"));
+		s = ctx.getServletContext().getResourceAsStream(
+		      basePath + "/" + systemId);
+	        if (s == null)
+		    throw new FileNotFoundException(
+			Resources.getMessage("UNABLE_TO_RESOLVE_ENTITY",
+			 systemId));
+	    }
+	    return new InputSource(s);
+        }
+    }
+
+    //*********************************************************************
+    // Tag attributes
+
+    public void setVar(String var) {
+	this.var = var;
+    }
+
+    public void setVarDom(String varDom) {
+	this.varDom = varDom;
+    }
+
+    public void setScope(String scope) {
+	this.scope = Util.getScope(scope);
+    }
+
+    public void setScopeDom(String scopeDom) {
+	this.scopeDom = Util.getScope(scopeDom);
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/common/xml/SetTag.java b/standard/src/org/apache/taglibs/standard/tag/common/xml/SetTag.java
new file mode 100644
index 0000000..763517a
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/common/xml/SetTag.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.common.xml;
+
+import java.util.List;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.PageContext;
+import javax.servlet.jsp.tagext.TagSupport;
+
+import org.apache.taglibs.standard.tag.common.core.Util;
+
+/**
+ * <p>Tag handler for <set> in JSTL's XML library.</p>
+ *
+ * @author Shawn Bayern
+ */
+public class SetTag extends TagSupport {
+
+    //*********************************************************************
+    // Internal state
+
+    private String select;                    // tag attribute
+    private String var;                       // tag attribute
+    private int scope;			      // processed tag attribute
+
+    //*********************************************************************
+    // Construction and initialization
+
+    /**
+     * Constructs a new handler.  As with TagSupport, subclasses should
+     * not provide other constructors and are expected to call the
+     * superclass constructor.
+     */
+    public SetTag() {
+        super();
+        init();
+    }
+
+    // resets local state
+    private void init() {
+	var = null;
+	select = null;
+        scope = PageContext.PAGE_SCOPE;
+    }
+
+
+    //*********************************************************************
+    // Tag logic
+
+    // applies XPath expression from 'select' and stores the result in 'var'
+    public int doStartTag() throws JspException {
+        // process the query
+        XPathUtil xu = new XPathUtil(pageContext);
+        List result =
+        xu.selectNodes(XPathUtil.getContext(this), select);
+        Object ret = result;
+        
+        // unwrap primitive types if that's what we received
+        if (result.size() == 1) {
+            Object o = result.get(0);
+            if (o instanceof String || o instanceof Boolean
+            || o instanceof Number)
+                ret = o;
+        }
+        
+        // expose the final result
+        pageContext.setAttribute(var, ret, scope);
+        return SKIP_BODY;
+    }
+
+    // Releases any resources we may have (or inherit)
+    public void release() {
+        super.release();
+        init();
+    }
+
+
+    //*********************************************************************
+    // Attribute accessors
+
+    public void setSelect(String select) {
+	this.select = select;
+    }
+
+    public void setVar(String var) {
+	this.var = var;
+    }
+
+    public void setScope(String scope) {
+	this.scope = Util.getScope(scope);
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/common/xml/TransformSupport.java b/standard/src/org/apache/taglibs/standard/tag/common/xml/TransformSupport.java
new file mode 100644
index 0000000..65d56f5
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/common/xml/TransformSupport.java
@@ -0,0 +1,381 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.common.xml;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.Writer;
+import java.util.List;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.JspTagException;
+import javax.servlet.jsp.PageContext;
+import javax.servlet.jsp.tagext.BodyTagSupport;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.Result;
+import javax.xml.transform.Source;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.URIResolver;
+import javax.xml.transform.dom.DOMResult;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.sax.SAXSource;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.stream.StreamSource;
+
+import org.apache.taglibs.standard.resources.Resources;
+import org.apache.taglibs.standard.tag.common.core.ImportSupport;
+import org.apache.taglibs.standard.tag.common.core.Util;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.XMLReaderFactory;
+
+/**
+ * <p>Support for tag handlers for <transform>, the XML transformation
+ * tag.</p>
+ *
+ * @author Shawn Bayern
+ */
+public abstract class TransformSupport extends BodyTagSupport {
+
+    //*********************************************************************
+    // Protected state
+
+    protected Object xml;                       // attribute
+    protected String xmlSystemId;		// attribute
+    protected Object xslt;			// attribute
+    protected String xsltSystemId;		// attribute
+    protected Result result;			// attribute
+
+    //*********************************************************************
+    // Private state
+
+    private String var;                            // 'var' attribute
+    private int scope;				   // processed 'scope' attr
+    private Transformer t;			   // actual Transformer
+    private TransformerFactory tf;		   // reusable factory
+    private DocumentBuilder db;			   // reusable factory
+    private DocumentBuilderFactory dbf;		   // reusable factory
+
+
+    //*********************************************************************
+    // Constructor and initialization
+
+    public TransformSupport() {
+	super();
+	init();
+    }
+
+    private void init() {
+	xml = xslt = null;
+	xmlSystemId = xsltSystemId = null;
+	var = null;
+	result = null;
+	tf = null;
+        scope = PageContext.PAGE_SCOPE;
+    }
+
+
+    //*********************************************************************
+    // Tag logic
+
+    public int doStartTag() throws JspException {
+      /*
+       * We can set up our Transformer here, so we do so, and we let
+       * it receive parameters directly from subtags (instead of
+       * caching them.
+       */
+      try {
+
+	//************************************
+	// Initialize
+
+	// set up our DocumentBuilderFactory if necessary
+	if (dbf == null) {
+	    dbf = DocumentBuilderFactory.newInstance();
+            dbf.setNamespaceAware(true);
+            dbf.setValidating(false);
+	}
+        if (db == null)
+	    db = dbf.newDocumentBuilder();
+
+	// set up the TransformerFactory if necessary
+        if (tf == null)
+            tf = TransformerFactory.newInstance();
+
+	//************************************
+	// Produce transformer
+
+	Source s;
+	if (xslt != null) {
+	    if (!(xslt instanceof String) && !(xslt instanceof Reader)
+                    && !(xslt instanceof javax.xml.transform.Source))
+		throw new JspTagException(
+		    Resources.getMessage("TRANSFORM_XSLT_UNRECOGNIZED"));
+	    s = getSource(xslt, xsltSystemId);
+	} else {
+	    throw new JspTagException(
+	        Resources.getMessage("TRANSFORM_NO_TRANSFORMER"));
+        }
+	tf.setURIResolver(new JstlUriResolver(pageContext));
+        t = tf.newTransformer(s);
+
+	return EVAL_BODY_BUFFERED;
+
+      } catch (SAXException ex) {
+	throw new JspException(ex);
+      } catch (ParserConfigurationException ex) {
+	throw new JspException(ex);
+      } catch (IOException ex) {
+	throw new JspException(ex);
+      } catch (TransformerConfigurationException ex) {
+	throw new JspException(ex);
+      }
+    }
+
+    // parse 'xml' or body, transform via our Transformer,
+    // and store as 'var' or through 'result'
+    public int doEndTag() throws JspException {
+      try {
+
+	//************************************
+	// Determine source XML
+
+	// if we haven't gotten a source, use the body (which may be empty)
+	Object xml = this.xml;
+	if (xml == null)				// still equal
+	    if (bodyContent != null && bodyContent.getString() != null)
+	        xml = bodyContent.getString().trim();
+	    else
+		xml = "";
+
+	// let the Source be with you
+	Source source = getSource(xml, xmlSystemId);
+
+	//************************************
+	// Conduct the transformation
+
+	// we can assume at most one of 'var' or 'result' is specified
+	if (result != null)
+	    // we can write directly to the Result
+	    t.transform(source, result);
+	else if (var != null) {
+	    // we need a Document
+	    Document d = db.newDocument();
+	    Result doc = new DOMResult(d);
+	    t.transform(source, doc);
+	    pageContext.setAttribute(var, d, scope);
+	} else {
+	    Result page =
+		new StreamResult(new SafeWriter(pageContext.getOut()));
+	    t.transform(source, page);
+	}
+
+	return EVAL_PAGE;
+      } catch (SAXException ex) {
+	throw new JspException(ex);
+      } catch (ParserConfigurationException ex) {
+	throw new JspException(ex);
+      } catch (IOException ex) {
+	throw new JspException(ex);
+      } catch (TransformerException ex) {
+	throw new JspException(ex);
+      }
+    }
+
+    // Releases any resources we may have (or inherit)
+    public void release() {
+	init();
+    }
+
+
+    //*********************************************************************
+    // Public methods for subtags
+
+    /** Sets (adds) a transformation parameter on our transformer. */
+    public void addParameter(String name, Object value) {
+	t.setParameter(name, value);
+    }
+
+
+    //*********************************************************************
+    // Utility methods
+
+    /**
+     * Wraps systemId with a "jstl:" prefix to prevent the parser from
+     * thinking that the URI is truly relative and resolving it against
+     * the current directory in the filesystem.
+     */
+    private static String wrapSystemId(String systemId) {
+      if (systemId == null)
+          return "jstl:";
+      else if (ImportSupport.isAbsoluteUrl(systemId))
+          return systemId;
+      else
+          return ("jstl:" + systemId);
+    }
+
+    /**
+     * Retrieves a Source from the given Object, whether it be a String,
+     * Reader, Node, or other supported types (even a Source already).
+     * If 'url' is true, then we must be passed a String and will interpret
+     * it as a URL.  A null input always results in a null output.
+     */
+    private Source getSource(Object o, String systemId)
+	    throws SAXException, ParserConfigurationException, IOException {
+	if (o == null)
+	    return null;
+        else if (o instanceof Source) {
+	    return (Source) o;
+        } else if (o instanceof String) {
+	    // if we've got a string, chain to Reader below
+	    return getSource(new StringReader((String) o), systemId);
+        } else if (o instanceof Reader) {
+	    // explicitly go through SAX to maintain control
+	    // over how relative external entities resolve
+            XMLReader xr = XMLReaderFactory.createXMLReader();
+            xr.setEntityResolver(
+                new ParseSupport.JstlEntityResolver(pageContext));
+            InputSource s = new InputSource((Reader) o);
+            s.setSystemId(wrapSystemId(systemId));
+            Source result = new SAXSource(xr, s);
+            result.setSystemId(wrapSystemId(systemId));
+	    return result;
+        } else if (o instanceof Node) {
+	    return new DOMSource((Node) o);
+        } else if (o instanceof List) {
+	    // support 1-item List because our XPath processor outputs them	
+	    List l = (List) o;
+	    if (l.size() == 1) {
+	        return getSource(l.get(0), systemId);		// unwrap List
+	    } else {
+	        throw new IllegalArgumentException(
+                  Resources.getMessage("TRANSFORM_SOURCE_INVALID_LIST"));
+	    }
+        } else {
+	    throw new IllegalArgumentException(
+	       Resources.getMessage("TRANSFORM_SOURCE_UNRECOGNIZED")
+	         + o.getClass());
+	}
+    }
+
+
+    //*********************************************************************
+    // Tag attributes
+
+    public void setVar(String var) {
+	this.var = var;
+    }
+
+    public void setScope(String scope) {
+        this.scope = Util.getScope(scope);
+    }
+
+
+    //*********************************************************************
+    // Private utility classes
+
+    /**
+     * A Writer based on a wrapped Writer but ignoring requests to
+     * close() and flush() it.  (Someone must have wrapped the
+     * toilet in my office similarly...)
+     */
+    private static class SafeWriter extends Writer {
+	private Writer w;
+	public SafeWriter(Writer w) { this.w = w; }
+	public void close() { }
+	public void flush() { }
+	public void write(char[] cbuf, int off, int len) throws IOException {
+	    w.write(cbuf, off, len);
+	}
+    }	
+
+    //*********************************************************************
+    // JSTL-specific URIResolver class
+
+    /** Lets us resolve relative external entities. */
+    private static class JstlUriResolver implements URIResolver {
+        private final PageContext ctx;
+        public JstlUriResolver(PageContext ctx) {
+            this.ctx = ctx;
+        }
+        public Source resolve(String href, String base)
+	        throws TransformerException {
+
+            // pass if we don't have a systemId
+            if (href == null)
+                return null;
+
+	    // remove "jstl" marker from 'base'
+            // NOTE: how 'base' is determined varies among different Xalan
+            // xsltc implementations
+            int index;
+            if (base != null && (index = base.indexOf("jstl:")) != -1) {
+                base = base.substring(index + 5);
+            }  
+
+            // we're only concerned with relative URLs
+            if (ImportSupport.isAbsoluteUrl(href)
+		    || (base != null && ImportSupport.isAbsoluteUrl(base)))
+                return null;
+
+	    // base is relative; remove everything after trailing '/'
+	    if (base == null || base.lastIndexOf("/") == -1)
+		base = "";
+	    else
+		base = base.substring(0, base.lastIndexOf("/") + 1);
+
+	    // concatenate to produce the real URL we're interested in
+	    String target = base + href;	    
+
+            // for relative URLs, load and wrap the resource.
+            // don't bother checking for 'null' since we specifically want
+            // the parser to fail if the resource doesn't exist
+            InputStream s;
+            if (target.startsWith("/")) {
+                s = ctx.getServletContext().getResourceAsStream(target);
+                if (s == null)
+                    throw new TransformerException(
+                        Resources.getMessage("UNABLE_TO_RESOLVE_ENTITY",
+                         href));
+            } else {
+                String pagePath =
+                    ((HttpServletRequest) ctx.getRequest()).getServletPath();
+                String basePath =
+                    pagePath.substring(0, pagePath.lastIndexOf("/"));
+                s = ctx.getServletContext().getResourceAsStream(
+                      basePath + "/" + target);
+		if (s == null)
+		    throw new TransformerException(
+                        Resources.getMessage("UNABLE_TO_RESOLVE_ENTITY",
+                         href));
+            }
+            return new StreamSource(s);
+        }
+    }
+
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/common/xml/UnresolvableException.java b/standard/src/org/apache/taglibs/standard/tag/common/xml/UnresolvableException.java
new file mode 100644
index 0000000..40a5f76
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/common/xml/UnresolvableException.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.common.xml;
+
+import org.apache.xpath.XPathException;
+
+/**
+ * <meta name="usage" content="general"/>
+ * Derived from XPathException in order that XPath processor
+ * exceptions may be specifically caught.
+ */
+public class UnresolvableException extends XPathException {
+    /**
+     * Create an UnresolvableException object that holds
+     * an error message.
+     * @param message The error message.
+     */
+    public UnresolvableException(String message) {
+        super(message);
+    }
+    
+    /**
+     * Create an UnresolvableException object that holds
+     * an error message, and another exception
+     * that caused this exception.
+     * @param message The error message.
+     * @param e The exception that caused this exception.
+     */
+    public UnresolvableException(String message, Exception e) {
+        super(message, e);
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/common/xml/WhenTag.java b/standard/src/org/apache/taglibs/standard/tag/common/xml/WhenTag.java
new file mode 100644
index 0000000..dbe7fb3
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/common/xml/WhenTag.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.common.xml;
+
+import javax.servlet.jsp.JspTagException;
+
+import org.apache.taglibs.standard.tag.common.core.WhenTagSupport;
+
+/**
+ * <p>Tag handler for <if> in JSTL's XML library.</p>
+ *
+ * @author Shawn Bayern
+ */
+
+public class WhenTag extends WhenTagSupport {
+
+    //*********************************************************************
+    // Constructor and lifecycle management
+
+    // initialize inherited and local state
+    public WhenTag() {
+        super();
+        init();
+    }
+
+    // Releases any resources we may have (or inherit)
+    public void release() {
+        super.release();
+        init();
+    }
+
+
+    //*********************************************************************
+    // Supplied conditional logic
+
+    protected boolean condition() throws JspTagException {
+        XPathUtil xu = new XPathUtil(pageContext);
+        return (xu.booleanValueOf(XPathUtil.getContext(this), select));
+    }
+
+    //*********************************************************************
+    // Private state
+
+    private String select;               // the value of the 'test' attribute
+
+
+    //*********************************************************************
+    // Attribute accessors
+
+    public void setSelect(String select) {
+        this.select = select;
+    }
+
+
+    //*********************************************************************
+    // Private utility methods
+
+    // resets internal state
+    private void init() {
+        select = null;
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/common/xml/XPathUtil.java b/standard/src/org/apache/taglibs/standard/tag/common/xml/XPathUtil.java
new file mode 100644
index 0000000..9b66d73
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/common/xml/XPathUtil.java
@@ -0,0 +1,887 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.common.xml;
+
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Vector;
+
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.jsp.JspTagException;
+import javax.servlet.jsp.PageContext;
+import javax.servlet.jsp.tagext.Tag;
+import javax.servlet.jsp.tagext.TagSupport;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.transform.TransformerException;
+
+import org.apache.taglibs.standard.resources.Resources;
+import org.apache.xml.utils.QName;
+import org.apache.xpath.VariableStack;
+import org.apache.xpath.XPathContext;
+import org.apache.xpath.objects.XBoolean;
+import org.apache.xpath.objects.XNodeSetForDOM;
+import org.apache.xpath.objects.XNumber;
+import org.apache.xpath.objects.XObject;
+import org.apache.xpath.objects.XString;
+import org.w3c.dom.DOMImplementation;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+/**
+ * <p>Support for tag handlers that evaluate XPath expressions.</p>
+ *
+ * @author Shawn Bayern
+ * @author Ramesh Mandava ( ramesh.mandava at sun.com )
+ * @author Pierre Delisle ( pierre.delisle at sun.com )
+ */
+// would ideally be a base class, but some of our user handlers already
+// have their own parents
+public class XPathUtil {
+    
+    //*********************************************************************
+    // Constructor
+    
+    /**
+     * Constructs a new XPathUtil object associated with the given
+     * PageContext.
+     */
+    public XPathUtil(PageContext pc) {
+        pageContext = pc;
+    }    
+    
+    int globalVarSize=0;
+    public Vector getVariableQNames ( ) {
+
+        globalVarSize = 0;
+        Vector variableVector = new Vector ( );
+        // Now construct attributes in different scopes
+        Enumeration enum_ = pageContext.getAttributeNamesInScope( 
+            PageContext.PAGE_SCOPE );
+        while ( enum_.hasMoreElements() ) {
+            String varName = (String)enum_.nextElement();
+            QName varQName = new QName ( PAGE_NS_URL, PAGE_P, varName); 
+            //Adding both namespace qualified QName and just localName
+            variableVector.addElement( varQName );
+            globalVarSize++;
+            
+            variableVector.addElement( new QName(null, varName ) );
+            globalVarSize++;
+        }
+        enum_ = pageContext.getAttributeNamesInScope( 
+            PageContext.REQUEST_SCOPE );
+        while ( enum_.hasMoreElements() ) {
+            String varName = (String)enum_.nextElement();
+            QName varQName = new QName ( REQUEST_NS_URL,REQUEST_P, varName); 
+            //Adding both namespace qualified QName and just localName
+            variableVector.addElement( varQName );
+            globalVarSize++;
+            variableVector.addElement( new QName(null, varName ) );
+            globalVarSize++;
+        }
+        enum_ = pageContext.getAttributeNamesInScope( 
+            PageContext.SESSION_SCOPE );
+        while ( enum_.hasMoreElements() ) {
+            String varName = (String)enum_.nextElement();
+            QName varQName = new QName ( SESSION_NS_URL, SESSION_P,varName); 
+            //Adding both namespace qualified QName and just localName
+            variableVector.addElement( varQName );
+            globalVarSize++;
+            variableVector.addElement( new QName(null, varName ) );
+            globalVarSize++;
+        }
+        enum_ = pageContext.getAttributeNamesInScope( 
+            PageContext.APPLICATION_SCOPE );
+        while ( enum_.hasMoreElements() ) {
+            String varName = (String)enum_.nextElement();
+            QName varQName = new QName ( APP_NS_URL, APP_P,varName ); 
+            //Adding both namespace qualified QName and just localName
+            variableVector.addElement( varQName );
+            globalVarSize++;
+            variableVector.addElement( new QName(null, varName ) );
+            globalVarSize++;
+        }
+        enum_ = pageContext.getRequest().getParameterNames();
+        while ( enum_.hasMoreElements() ) {
+            String varName = (String)enum_.nextElement();
+            QName varQName = new QName ( PARAM_NS_URL, PARAM_P,varName ); 
+            //Adding both namespace qualified QName and just localName
+            variableVector.addElement( varQName );
+            globalVarSize++;
+        }
+        enum_ = pageContext.getServletContext().getInitParameterNames();
+        while ( enum_.hasMoreElements() ) {
+            String varName = (String)enum_.nextElement();
+            QName varQName = new QName ( INITPARAM_NS_URL, INITPARAM_P,varName ); 
+            //Adding both namespace qualified QName and just localName
+            variableVector.addElement( varQName );
+            globalVarSize++;
+        }
+        enum_ = ((HttpServletRequest)pageContext.getRequest()).getHeaderNames();
+        while ( enum_.hasMoreElements() ) {
+            String varName = (String)enum_.nextElement();
+            QName varQName = new QName ( HEADER_NS_URL, HEADER_P,varName ); 
+            //Adding namespace qualified QName 
+            variableVector.addElement( varQName );
+            globalVarSize++;
+        }
+        Cookie[] c= ((HttpServletRequest)pageContext.getRequest()).getCookies();
+        if ( c!= null ) {
+	    for (int i = 0; i < c.length; i++) {
+	        String varName = c[i].getName();
+                QName varQName = new QName ( COOKIE_NS_URL, COOKIE_P,varName ); 
+                //Adding namespace qualified QName 
+                variableVector.addElement( varQName );
+                globalVarSize++;
+            }
+        }
+
+        return variableVector;
+        
+    }
+ 
+    //*********************************************************************
+    // Support for JSTL variable resolution
+    
+    // The URLs
+    private static final String PAGE_NS_URL
+    = "http://java.sun.com/jstl/xpath/page";
+    private static final String REQUEST_NS_URL
+    = "http://java.sun.com/jstl/xpath/request";
+    private static final String SESSION_NS_URL
+    = "http://java.sun.com/jstl/xpath/session";
+    private static final String APP_NS_URL
+    = "http://java.sun.com/jstl/xpath/app";
+    private static final String PARAM_NS_URL
+    = "http://java.sun.com/jstl/xpath/param";
+    private static final String INITPARAM_NS_URL
+    = "http://java.sun.com/jstl/xpath/initParam";
+    private static final String COOKIE_NS_URL
+    = "http://java.sun.com/jstl/xpath/cookie";
+    private static final String HEADER_NS_URL
+    = "http://java.sun.com/jstl/xpath/header";
+    
+    // The prefixes
+    private static final String PAGE_P = "pageScope";
+    private static final String REQUEST_P = "requestScope";
+    private static final String SESSION_P = "sessionScope";
+    private static final String APP_P = "applicationScope";
+    private static final String PARAM_P = "param";
+    private static final String INITPARAM_P = "initParam";
+    private static final String COOKIE_P = "cookie";
+    private static final String HEADER_P = "header";
+    
+    /**
+     * org.apache.xpath.VariableStack defines a class to keep track of a stack 
+     * for template arguments and variables. 
+     * JstlVariableContext customizes it so it handles JSTL custom
+     * variable-mapping rules.
+     */
+    protected class JstlVariableContext extends org.apache.xpath.VariableStack {
+        
+        public JstlVariableContext( ) {
+            super();
+        }
+        
+        /**
+         * Get a variable as an XPath object based on it's qualified name.
+         * We override the base class method so JSTL's custom variable-mapping 
+         * rules can be applied.
+         *
+         * @param xctxt The XPath context. @@@ we don't use it...
+         *  (from xalan: which must be passed in order to lazy evaluate variables.)
+         * @param qname The qualified name of the variable.
+         */
+        public XObject getVariableOrParam(
+        XPathContext xctxt, 
+        org.apache.xml.utils.QName qname)
+        throws javax.xml.transform.TransformerException, UnresolvableException
+        {
+            //p( "***********************************getVariableOrParam begin****");
+            String namespace = qname.getNamespaceURI();
+            String prefix = qname.getPrefix();
+            String localName = qname.getLocalName();
+            
+            //p("namespace:prefix:localname=>"+ namespace
+            //     + ":" + prefix +":" + localName );
+            
+            try {
+                Object varObject = getVariableValue(namespace,prefix,localName);
+
+
+                //XObject varObject = myvs.getVariableOrParam( xpathSupport, varQName);
+                XObject newXObject = new XObject( varObject);
+
+                if ( Class.forName("org.w3c.dom.Document").isInstance( varObject) ) {
+
+                    NodeList nl= ((Document)varObject).getChildNodes();
+                    // To allow non-welformed document
+                    Vector nodeVector = new Vector();
+                    for ( int i=0; i<nl.getLength(); i++ ) {
+                        Node currNode = nl.item(i);
+                        if ( currNode.getNodeType() == Node.ELEMENT_NODE ) {
+                            nodeVector.addElement( currNode);
+                        }
+                    }
+                    JSTLNodeList jstlNodeList = new JSTLNodeList( nodeVector);
+                    newXObject = new XNodeSetForDOM( jstlNodeList, xctxt );
+                    
+                    return newXObject;
+                   
+                } 
+                if ( Class.forName(
+        "org.apache.taglibs.standard.tag.common.xml.JSTLNodeList").isInstance(
+                     varObject) ) {
+                    JSTLNodeList jstlNodeList = (JSTLNodeList)varObject;
+                    if  ( ( jstlNodeList.getLength() == 1 ) && 
+   (!Class.forName("org.w3c.dom.Node").isInstance( jstlNodeList.elementAt(0) ) ) ) { 
+                        varObject = jstlNodeList.elementAt(0);
+                        //Now we need to allow this primitive type to be coverted 
+                        // to type which Xalan XPath understands 
+                    } else {
+                        return new XNodeSetForDOM (  jstlNodeList ,xctxt );
+                    }
+                } 
+                if (Class.forName("org.w3c.dom.Node").isInstance( varObject)) {
+                    newXObject = new XNodeSetForDOM ( new JSTLNodeList( (Node)varObject ),xctxt );
+                } else if ( Class.forName("java.lang.String").isInstance( varObject)){
+                    newXObject = new XString ( (String)varObject );
+                } else if ( Class.forName("java.lang.Boolean").isInstance( varObject) ) {
+                    newXObject = new XBoolean ( (Boolean)varObject );
+                } else if ( Class.forName("java.lang.Number").isInstance( varObject) ) {
+                    newXObject = new XNumber ( (Number)varObject );
+                } 
+
+                return newXObject;
+               // myvs.setGlobalVariable( i, newXObject );
+            } catch ( ClassNotFoundException cnfe ) {
+                // This shouldn't happen (FIXME: LOG)
+                System.out.println("CLASS NOT FOUND EXCEPTION :" + cnfe );
+            } 
+            //System.out.println("*****getVariableOrParam returning *null*" );
+            return null ;
+        }
+        
+        /**
+         * Retrieve an XPath's variable value using JSTL's custom 
+         * variable-mapping rules
+         */
+        public Object getVariableValue(
+        String namespace, 
+        String prefix,
+        String localName) 
+        throws UnresolvableException 
+        {
+            // p("resolving: ns=" + namespace + " prefix=" + prefix + " localName=" + localName);
+            // We can match on namespace with Xalan but leaving as is
+            // [ I 'd prefer to match on namespace, but this doesn't appear
+            // to work in Jaxen]
+            if (prefix == null || prefix.equals("")) {
+                return notNull(
+                pageContext.findAttribute(localName),
+                prefix,
+                localName);
+            } else if (prefix.equals(PAGE_P)) {
+                return notNull(
+                pageContext.getAttribute(localName,PageContext.PAGE_SCOPE),
+                prefix,
+                localName);
+            } else if (prefix.equals(REQUEST_P)) {
+                return notNull(
+                pageContext.getAttribute(localName,
+                PageContext.REQUEST_SCOPE),
+                prefix,
+                localName);
+            } else if (prefix.equals(SESSION_P)) {
+                return notNull(
+                pageContext.getAttribute(localName,
+                PageContext.SESSION_SCOPE),
+                prefix,
+                localName);
+            } else if (prefix.equals(APP_P)) {
+                return notNull(
+                pageContext.getAttribute(localName,
+                PageContext.APPLICATION_SCOPE),
+                prefix,
+                localName);
+            } else if (prefix.equals(PARAM_P)) {
+                return notNull(
+                pageContext.getRequest().getParameter(localName),
+                prefix,
+                localName);
+            } else if (prefix.equals(INITPARAM_P)) {
+                return notNull(
+                pageContext.getServletContext().
+                getInitParameter(localName),
+                prefix,
+                localName);
+            } else if (prefix.equals(HEADER_P)) {
+                HttpServletRequest hsr =
+                (HttpServletRequest) pageContext.getRequest();
+                return notNull(
+                hsr.getHeader(localName),
+                prefix,
+                localName);
+            } else if (prefix.equals(COOKIE_P)) {
+                HttpServletRequest hsr =
+                (HttpServletRequest) pageContext.getRequest();
+                Cookie[] c = hsr.getCookies();
+                for (int i = 0; i < c.length; i++)
+                    if (c[i].getName().equals(localName))
+                        return c[i].getValue();
+                throw new UnresolvableException("$" + prefix + ":" + localName);
+            } else {
+                throw new UnresolvableException("$" + prefix + ":" + localName);
+            }
+        }    
+        
+        /**
+         * Validate that the Object returned is not null. If it is
+         * null, throw an exception.
+         */
+        private Object notNull(Object o, String prefix, String localName)
+        throws UnresolvableException {
+            if (o == null) {
+                throw new UnresolvableException("$" + (prefix==null?"":prefix+":") + localName);
+            }
+            //p("resolved to: " + o);
+            return o;
+        }                
+    }
+    
+    //*********************************************************************
+    // Support for XPath evaluation
+    
+    private PageContext pageContext;
+    private static HashMap exprCache;
+    private static JSTLPrefixResolver jstlPrefixResolver = null;
+    
+    /** Initialize globally useful data. */
+    private synchronized static void staticInit() {
+        if (jstlPrefixResolver == null) {
+            // register supported namespaces
+            jstlPrefixResolver = new JSTLPrefixResolver();
+            jstlPrefixResolver.addNamespace("pageScope", PAGE_NS_URL);
+            jstlPrefixResolver.addNamespace("requestScope", REQUEST_NS_URL);
+            jstlPrefixResolver.addNamespace("sessionScope", SESSION_NS_URL);
+            jstlPrefixResolver.addNamespace("applicationScope", APP_NS_URL);
+            jstlPrefixResolver.addNamespace("param", PARAM_NS_URL);
+            jstlPrefixResolver.addNamespace("initParam", INITPARAM_NS_URL);
+            jstlPrefixResolver.addNamespace("header", HEADER_NS_URL);
+            jstlPrefixResolver.addNamespace("cookie", COOKIE_NS_URL);
+            
+            
+            // create a HashMap to cache the expressions
+            exprCache = new HashMap();
+        }
+    }
+    
+    static DocumentBuilderFactory dbf = null;
+    static DocumentBuilder db = null;
+    static Document d = null;
+    
+    static Document getDummyDocument( ) {
+        try {
+            if ( dbf == null ) {
+                dbf = DocumentBuilderFactory.newInstance();
+                dbf.setNamespaceAware( true );
+                dbf.setValidating( false );
+            }
+            db = dbf.newDocumentBuilder();
+
+            DOMImplementation dim = db.getDOMImplementation();
+            d = dim.createDocument("http://java.sun.com/jstl", "dummyroot", null); 
+            //d = db.newDocument();
+            return d;
+        } catch ( Exception e ) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+     static Document getDummyDocumentWithoutRoot( ) {
+        try {
+            if ( dbf == null ) {
+                dbf = DocumentBuilderFactory.newInstance();
+                dbf.setNamespaceAware( true );
+                dbf.setValidating( false );
+            }
+            db = dbf.newDocumentBuilder();
+
+            d = db.newDocument();
+            return d;
+        } catch ( Exception e ) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    private static Document getDocumentForNode(Node node) {
+        Document doc = getDummyDocumentWithoutRoot();
+        Node importedNode = doc.importNode(node, true);
+        doc.appendChild(importedNode);
+        return doc;
+    }
+    
+    // The following variable is used for holding the modified xpath string
+    // when adapting parameter for Xalan XPath engine, where we need to have
+    // a Non null context node.
+    String modifiedXPath = null;
+    
+
+    
+    
+    
+    /**
+     * Evaluate an XPath expression to a String value. 
+     */
+    public String valueOf(Node n, String xpath) throws JspTagException  {
+        //p("******** valueOf(" + n + ", " + xpath + ")");
+        staticInit();
+        // @@@ but where do we set the Pag4eContext for the varaiblecontext?
+        JstlVariableContext vs = new JstlVariableContext();
+        XPathContext xpathSupport = new XPathContext();
+        xpathSupport.setVarStack( vs);
+        
+        Vector varVector = fillVarStack(vs, xpathSupport);                
+        
+        Node contextNode = adaptParamsForXalan( vs, n, xpath.trim() );
+        
+        xpath = modifiedXPath;
+        
+        //p("******** valueOf: modified xpath: " + xpath);
+
+        XObject result = JSTLXPathAPI.eval( contextNode, xpath,
+        jstlPrefixResolver,xpathSupport, varVector);
+
+        
+        //p("******Result TYPE => " + result.getTypeString() );
+        
+        String resultString = result.str();
+        //p("******** valueOf: after eval: " + resultString);
+        
+        return resultString;
+    
+    }    
+
+    /** 
+     * Evaluate an XPath expression to a boolean value. 
+     */
+    public boolean booleanValueOf(Node n, String xpath)
+    throws JspTagException {
+        
+        staticInit();
+        JstlVariableContext vs = new JstlVariableContext();
+        XPathContext xpathSupport = new XPathContext();
+        xpathSupport.setVarStack( vs);
+        
+        Vector varVector = fillVarStack(vs, xpathSupport);        
+        
+        Node contextNode = adaptParamsForXalan( vs, n, xpath.trim() );
+        xpath = modifiedXPath;
+        
+        XObject result = JSTLXPathAPI.eval( contextNode, xpath,
+        jstlPrefixResolver, xpathSupport, varVector);
+        
+        try {
+            return result.bool();
+        } catch (TransformerException ex) {
+            throw new JspTagException(
+                Resources.getMessage("XPATH_ERROR_XOBJECT", ex.toString()), ex);            
+        }
+    }
+    
+    /** 
+     * Evaluate an XPath expression to a List of nodes. 
+     */
+    public List selectNodes(Node n, String xpath)  throws JspTagException {
+        
+        staticInit();
+        JstlVariableContext vs = new JstlVariableContext();
+        XPathContext xpathSupport = new XPathContext();
+        xpathSupport.setVarStack( vs);
+        
+        Vector varVector = fillVarStack(vs, xpathSupport);                
+
+        Node contextNode = adaptParamsForXalan( vs, n, xpath.trim() );
+        xpath = modifiedXPath;
+        
+        XObject result = JSTLXPathAPI.eval( contextNode, xpath,
+        jstlPrefixResolver,xpathSupport, varVector);
+        try {
+            NodeList nl= JSTLXPathAPI.getNodeList(result);
+            return new JSTLNodeList( nl );
+        } catch ( JspTagException e ) {
+            try { 
+                //If result can't be converted to NodeList we receive exception
+                // In this case we may have single primitive value as the result
+                // Populating List with this value ( String, Boolean or Number )
+
+                //System.out.println("JSTLXPathAPI.getNodeList thrown exception:"+ e);
+                Vector vector = new Vector();
+                Object resultObject = null;
+                if ( result.getType()== XObject.CLASS_BOOLEAN ) {
+                    resultObject = new Boolean( result.bool());
+                } else if ( result.getType()== XObject.CLASS_NUMBER ) {
+                    resultObject = new Double( result.num());
+                } else if ( result.getType()== XObject.CLASS_STRING ) {
+                    resultObject = result.str();
+                }
+
+                vector.add( resultObject );
+                return new JSTLNodeList ( vector );
+            } catch ( TransformerException te ) {
+                throw new JspTagException(te.toString(), te);
+            }
+        }
+          
+        
+       
+    }
+    
+    /** 
+     * Evaluate an XPath expression to a single node. 
+     */
+    public Node selectSingleNode(Node n, String xpath)
+    throws JspTagException {
+        //p("selectSingleNode of XPathUtil = passed node:" +
+        //   "xpath => " + n + " : " + xpath );
+        
+        staticInit();
+        JstlVariableContext vs = new JstlVariableContext();
+        XPathContext xpathSupport = new XPathContext();
+        xpathSupport.setVarStack( vs);
+        
+        Vector varVector = fillVarStack(vs, xpathSupport);                
+
+        Node contextNode = adaptParamsForXalan( vs, n, xpath.trim() );
+        xpath = modifiedXPath;
+        
+        return (Node) JSTLXPathAPI.selectSingleNode( contextNode, xpath,
+        jstlPrefixResolver,xpathSupport );
+    }
+    
+    /** Returns a locally appropriate context given a node. */
+    private VariableStack getLocalContext() {
+        // set up instance-specific contexts
+        VariableStack vc = new JstlVariableContext();
+        return vc;
+    }    
+    
+    //*********************************************************************
+    // Adapt XPath expression for integration with Xalan
+   
+    /**
+     * To evaluate an XPath expression using Xalan, we need 
+     * to create an XPath object, which wraps an expression object and provides 
+     * general services for execution of that expression.
+     *
+     * An XPath object can be instantiated with the following information:
+     *     - XPath expression to evaluate
+     *     - SourceLocator 
+     *        (reports where an error occurred in the XML source or 
+     *        transformation instructions)
+     *     - PrefixResolver
+     *        (resolve prefixes to namespace URIs)
+     *     - type
+     *        (one of SELECT or MATCH)
+     *     - ErrorListener
+     *        (customized error handling)
+     *
+     * Execution of the XPath expression represented by an XPath object
+     * is done via method execute which takes the following parameters:
+     *     - XPathContext 
+     *        The execution context
+     *     - Node contextNode
+     *        The node that "." expresses
+     *     - PrefixResolver namespaceContext
+     *        The context in which namespaces in the XPath are supposed to be 
+     *        expanded.
+     *
+     * Given all of this, if no context node is set for the evaluation
+     * of the XPath expression, one must be set so Xalan 
+     * can successfully evaluate a JSTL XPath expression.
+     * (it will not work if the context node is given as a varialbe
+     * at the beginning of the expression)
+     *
+     * @@@ Provide more details...
+     */
+    protected Node adaptParamsForXalan( JstlVariableContext jvc,  Node n,
+    String xpath ) {
+        Node boundDocument = null;
+        
+        modifiedXPath = xpath;
+        String origXPath = xpath ;
+        boolean whetherOrigXPath = true;
+        
+        // If contextNode is not null then  just pass the values to Xalan XPath
+        if ( n != null ) {
+            return n;
+        }
+        
+        if (  xpath.startsWith("$")  ) {
+            // JSTL uses $scopePrefix:varLocalName/xpath expression
+
+            String varQName=  xpath.substring( xpath.indexOf("$")+1);
+            if ( varQName.indexOf("/") > 0 ) {
+                varQName = varQName.substring( 0, varQName.indexOf("/"));
+            }
+            String varPrefix =  null;
+            String varLocalName =  varQName;
+            if ( varQName.indexOf( ":") >= 0 ) {
+                varPrefix = varQName.substring( 0, varQName.indexOf(":") );
+                varLocalName = varQName.substring( varQName.indexOf(":")+1 );
+            }
+            
+            if ( xpath.indexOf("/") > 0 ) {
+                xpath = xpath.substring( xpath.indexOf("/"));
+            } else  {
+                xpath = "/*";
+                whetherOrigXPath = false; 
+            }
+           
+            
+            try {
+                Object varObject=jvc.getVariableValue( null,varPrefix,
+                varLocalName);
+                //System.out.println( "varObject => : its Class " +varObject +
+                // ":" + varObject.getClass() );
+                
+                if ( Class.forName("org.w3c.dom.Document").isInstance(
+                varObject ) )  {
+                    //boundDocument = ((Document)varObject).getDocumentElement();
+                    boundDocument = ((Document)varObject);
+                } else {
+                    
+                    //System.out.println("Creating a Dummy document to pass " +
+                    // " onto as context node " );
+                    
+                    if ( Class.forName("org.apache.taglibs.standard.tag.common.xml.JSTLNodeList").isInstance( varObject ) ) {
+                        Document newDocument = getDummyDocument();
+
+                        JSTLNodeList jstlNodeList = (JSTLNodeList)varObject;
+                        if   ( jstlNodeList.getLength() == 1 ) { 
+                            if ( Class.forName("org.w3c.dom.Node").isInstance(
+                                jstlNodeList.elementAt(0) ) ) { 
+                                Node node = (Node)jstlNodeList.elementAt(0);
+                                boundDocument = getDocumentForNode(node);
+                                if ( whetherOrigXPath ) {
+                                    xpath="/*" + xpath;
+                                }
+
+                            } else {
+
+                                //Nodelist with primitive type
+                                Object myObject = jstlNodeList.elementAt(0);
+
+                                //p("Single Element of primitive type");
+                                //p("Type => " + myObject.getClass());
+
+                                xpath = myObject.toString();
+
+                                //p("String value ( xpathwould be this) => " + xpath);
+                                boundDocument = newDocument;
+                            } 
+                            
+                        } else {
+
+                            Element dummyroot = newDocument.getDocumentElement();
+                            for ( int i=0; i< jstlNodeList.getLength(); i++ ) {
+                                Node currNode = (Node)jstlNodeList.item(i);
+                            
+                                Node importedNode = newDocument.importNode(
+                                    currNode, true );
+
+                                //printDetails ( newDocument);
+
+                                dummyroot.appendChild( importedNode );
+
+                                //p( "Details of the document After importing");
+                                //printDetails ( newDocument);
+                            }
+                            boundDocument = newDocument;
+                            // printDetails ( boundDocument );
+                            //Verify :As we are adding Document element we need
+                            // to change the xpath expression.Hopefully this
+                            // won't  change the result
+
+                            xpath = "/*" +  xpath;
+                        }
+                    } else if ( Class.forName("org.w3c.dom.Node").isInstance(
+                    varObject ) ) {
+                        boundDocument = getDocumentForNode((Node)varObject);
+                        if (whetherOrigXPath) {
+                            xpath = "/*" + xpath;
+                        }
+                    } else {
+                        boundDocument = getDummyDocument();
+                        xpath = origXPath;
+                    }
+                    
+                    
+                }
+            } catch ( UnresolvableException ue ) {
+                // FIXME: LOG
+                System.out.println("Variable Unresolvable :" + ue.getMessage());
+                ue.printStackTrace();
+            } catch ( ClassNotFoundException cnf ) {
+                // Will never happen
+            }
+        } else { 
+            //System.out.println("Not encountered $ Creating a Dummydocument 2 "+
+             //   "pass onto as context node " );
+            boundDocument = getDummyDocument();
+        }
+     
+        modifiedXPath = xpath;
+        //System.out.println("Modified XPath::boundDocument =>" + modifiedXPath +
+        //    "::" + boundDocument );
+         
+        return boundDocument;
+    }
+    
+
+    //*********************************************************************
+    // 
+    
+    /**
+     ** @@@ why do we have to pass varVector in the varStack first, and then
+     * to XPath object?
+     */
+    private Vector fillVarStack(JstlVariableContext vs, XPathContext xpathSupport) 
+    throws JspTagException {
+        org.apache.xpath.VariableStack myvs = xpathSupport.getVarStack();
+        Vector varVector = getVariableQNames();
+        for ( int i=0; i<varVector.size(); i++ ) {
+          
+            QName varQName = (QName)varVector.elementAt(i);
+
+            try { 
+                XObject variableValue = vs.getVariableOrParam( xpathSupport, varQName );
+                //p("&&&&Variable set to => " + variableValue.toString() );
+                //p("&&&&Variable type => " + variableValue.getTypeString() );
+                myvs.setGlobalVariable( i, variableValue );
+
+            } catch ( TransformerException te ) {
+                throw new JspTagException(te.toString(), te);
+            } 
+ 
+        }
+        return varVector;
+    }
+        
+    
+    
+    
+    
+    //*********************************************************************
+    // Static support for context retrieval from parent <forEach> tag
+    
+    public static Node getContext(Tag t) throws JspTagException {
+        ForEachTag xt =
+        (ForEachTag) TagSupport.findAncestorWithClass(
+        t, ForEachTag.class);
+        if (xt == null)
+            return null;
+        else
+            return (xt.getContext());
+    }
+    
+    //*********************************************************************
+    // Utility methods
+    
+    private static void p(String s) {
+        System.out.println("[XPathUtil] " + s);
+    }
+    
+    public static void printDetails(Node n) {
+        System.out.println("\n\nDetails of Node = > " + n ) ;
+        System.out.println("Name:Type:Node Value = > " + n.getNodeName() +
+        ":" + n.getNodeType() + ":" + n.getNodeValue()  ) ;
+        System.out.println("Namespace URI : Prefix : localName = > " +
+        n.getNamespaceURI() + ":" +n.getPrefix() + ":" + n.getLocalName());
+        System.out.println("\n Node has children => " + n.hasChildNodes() );
+        if ( n.hasChildNodes() ) {
+            NodeList nl = n.getChildNodes();
+            System.out.println("Number of Children => " + nl.getLength() );
+            for ( int i=0; i<nl.getLength(); i++ ) {
+                Node childNode = nl.item(i);
+                printDetails( childNode );
+            }
+        }
+    }    
+}
+
+class JSTLNodeList extends Vector implements NodeList   {
+    
+    Vector nodeVector;
+
+    public JSTLNodeList ( Vector nodeVector ) {
+        this.nodeVector = nodeVector;
+    }
+
+    public JSTLNodeList ( NodeList nl ) {
+        nodeVector = new Vector();
+        //System.out.println("[JSTLNodeList] nodelist details");
+        for ( int i=0; i<nl.getLength(); i++ ) {
+            Node currNode = nl.item(i);
+            //XPathUtil.printDetails ( currNode );
+            nodeVector.add(i, nl.item(i) );
+        }
+    }
+
+    public JSTLNodeList ( Node n ) {
+        nodeVector = new Vector();
+        nodeVector.addElement( n );
+    }
+        
+
+    public Node item ( int index ) {
+        return (Node)nodeVector.elementAt( index );
+    }
+
+    public Object elementAt ( int index ) {
+        return nodeVector.elementAt( index );
+    }
+
+    public Object get ( int index ) {
+        return nodeVector.get( index );
+    }
+
+    public int getLength (  ) {
+        return nodeVector.size( );
+    }
+
+    public int size (  ) {
+        //System.out.println("JSTL node list size => " + nodeVector.size() );
+        return nodeVector.size( );
+    }
+
+    // Can implement other Vector methods to redirect those methods to 
+    // the vector in the variable param. As we are not using them as part 
+    // of this implementation we are not doing that here. If this changes
+    // then we need to override those methods accordingly  
+
+}
+         
+
+
+
diff --git a/standard/src/org/apache/taglibs/standard/tag/el/core/ExpressionUtil.java b/standard/src/org/apache/taglibs/standard/tag/el/core/ExpressionUtil.java
new file mode 100644
index 0000000..440c6ab
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/el/core/ExpressionUtil.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.el.core;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.PageContext;
+import javax.servlet.jsp.tagext.Tag;
+
+import org.apache.taglibs.standard.lang.support.ExpressionEvaluatorManager;
+import org.apache.taglibs.standard.tag.common.core.NullAttributeException;
+
+/**
+ * <p>Contains some static utilities to facilitate common forms of
+ * expression evaluation.</p>
+ *
+ * @author Shawn Bayern
+ */
+
+public class ExpressionUtil {
+
+    /** Evaluates an expression if present, but does not allow the expression
+     *  to evaluate to 'null', throwing a NullAttributeException if it
+     *  does.  The function <b>can</b> return null, however, if the
+     *  expression itself is null.
+     */
+    public static Object evalNotNull(String tagName,
+				     String attributeName,
+	                             String expression,
+				     Class expectedType,
+				     Tag tag,
+	                             PageContext pageContext)
+	        throws JspException {
+        if (expression != null) {
+            Object r = ExpressionEvaluatorManager.evaluate(
+                attributeName, expression, expectedType, tag, pageContext);
+            if (r == null)
+                throw new NullAttributeException(tagName, attributeName);
+	    return r;
+        } else
+	    return null;
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/el/core/ForEachTag.java b/standard/src/org/apache/taglibs/standard/tag/el/core/ForEachTag.java
new file mode 100644
index 0000000..306c24c
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/el/core/ForEachTag.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.el.core;
+
+import java.util.ArrayList;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.jstl.core.LoopTag;
+import javax.servlet.jsp.tagext.IterationTag;
+
+import org.apache.taglibs.standard.lang.support.ExpressionEvaluatorManager;
+import org.apache.taglibs.standard.tag.common.core.ForEachSupport;
+import org.apache.taglibs.standard.tag.common.core.NullAttributeException;
+
+/**
+ * <p>A handler for <forEach> that accepts attributes as Strings
+ * and evaluates them as expressions at runtime.</p>
+ *
+ * @author Shawn Bayern
+ */
+
+public class ForEachTag
+    extends ForEachSupport
+    implements LoopTag, IterationTag
+{
+
+    //*********************************************************************
+    // 'Private' state (implementation details)
+
+    private String begin_;                      // stores EL-based property
+    private String end_;                        // stores EL-based property
+    private String step_;                       // stores EL-based property
+    private String items_;			// stores EL-based property
+
+
+    //*********************************************************************
+    // Constructor
+
+    public ForEachTag() {
+        super();
+        init();
+    }
+
+
+    //*********************************************************************
+    // Tag logic
+
+    /* Begins iterating by processing the first item. */
+    public int doStartTag() throws JspException {
+
+        // evaluate any expressions we were passed, once per invocation
+        evaluateExpressions();
+
+	// chain to the parent implementation
+	return super.doStartTag();
+    }
+
+
+    // Releases any resources we may have (or inherit)
+    public void release() {
+        super.release();
+        init();
+    }
+
+
+    //*********************************************************************
+    // Accessor methods
+
+    // for EL-based attribute
+    public void setBegin(String begin_) {
+        this.begin_ = begin_;
+        this.beginSpecified = true;
+    }
+
+    // for EL-based attribute
+    public void setEnd(String end_) {
+        this.end_ = end_;
+        this.endSpecified = true;
+    }
+
+    // for EL-based attribute
+    public void setStep(String step_) {
+        this.step_ = step_;
+        this.stepSpecified = true;
+    }
+
+    public void setItems(String items_) {
+        this.items_ = items_;
+    }
+
+    //*********************************************************************
+    // Private (utility) methods
+
+    // (re)initializes state (during release() or construction)
+    private void init() {
+        // defaults for interface with page author
+        begin_ = null;          // (no expression)
+        end_ = null;            // (no expression)
+        step_ = null;           // (no expression)
+	items_ = null;		// (no expression)
+    }
+
+    /* Evaluates expressions as necessary */
+    private void evaluateExpressions() throws JspException {
+        /* 
+         * Note: we don't check for type mismatches here; we assume
+         * the expression evaluator will return the expected type
+         * (by virtue of knowledge we give it about what that type is).
+         * A ClassCastException here is truly unexpected, so we let it
+         * propagate up.
+         */
+
+        if (begin_ != null) {
+            Object r = ExpressionEvaluatorManager.evaluate(
+                "begin", begin_, Integer.class, this, pageContext);
+	    if (r == null)
+		throw new NullAttributeException("forEach", "begin");
+            begin = ((Integer) r).intValue();
+            validateBegin();
+        }
+
+        if (end_ != null) {
+            Object r = ExpressionEvaluatorManager.evaluate(
+                "end", end_, Integer.class, this, pageContext);
+	    if (r == null)
+		throw new NullAttributeException("forEach", "end");
+            end = ((Integer) r).intValue();
+            validateEnd();
+        }
+
+        if (step_ != null) {
+            Object r = ExpressionEvaluatorManager.evaluate(
+                "step", step_, Integer.class, this, pageContext);
+	    if (r == null)
+		throw new NullAttributeException("forEach", "step");
+            step = ((Integer) r).intValue();
+            validateStep();
+        }
+
+	if (items_ != null) {
+            rawItems = ExpressionEvaluatorManager.evaluate(
+                "items", items_, Object.class, this, pageContext);
+	    // use an empty list to indicate "no iteration", if relevant
+	    if (rawItems == null)
+		rawItems = new ArrayList();
+        }
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/el/core/ForTokensTag.java b/standard/src/org/apache/taglibs/standard/tag/el/core/ForTokensTag.java
new file mode 100644
index 0000000..272bc14
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/el/core/ForTokensTag.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.el.core;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.jstl.core.LoopTag;
+import javax.servlet.jsp.tagext.IterationTag;
+
+import org.apache.taglibs.standard.lang.support.ExpressionEvaluatorManager;
+import org.apache.taglibs.standard.tag.common.core.ForTokensSupport;
+import org.apache.taglibs.standard.tag.common.core.NullAttributeException;
+
+/**
+ * <p>A handler for <forTokens> that accepts attributes as Strings
+ * and evaluates them as expressions at runtime.
+ *
+ * @author Shawn Bayern
+ */
+public class ForTokensTag
+    extends ForTokensSupport
+    implements LoopTag, IterationTag
+{
+
+    //*********************************************************************
+    // 'Private' state (implementation details)
+
+    private String begin_;                      // raw EL-based property
+    private String end_;                        // raw EL-based property
+    private String step_;                       // raw EL-based property
+    private String items_;			// raw EL-based property
+    private String delims_;			// raw EL-based property
+
+
+    //*********************************************************************
+    // Constructor
+
+    public ForTokensTag() {
+        super();
+        init();
+    }
+
+
+    //*********************************************************************
+    // Tag logic
+
+    /* Begins iterating by processing the first item. */
+    public int doStartTag() throws JspException {
+
+        // evaluate any expressions we were passed, once per invocation
+        evaluateExpressions();
+
+	// chain to the parent implementation
+	return super.doStartTag();
+    }
+
+
+    // Releases any resources we may have (or inherit)
+    public void release() {
+        super.release();
+        init();
+    }
+
+
+    //*********************************************************************
+    // Accessor methods
+
+    // for EL-based attribute
+    public void setBegin(String begin_) {
+        this.begin_ = begin_;
+        this.beginSpecified = true;
+    }
+
+    // for EL-based attribute
+    public void setEnd(String end_) {
+        this.end_ = end_;
+        this.endSpecified = true;
+    }
+
+    // for EL-based attribute
+    public void setStep(String step_) {
+        this.step_ = step_;
+        this.stepSpecified = true;
+    }
+
+    // for EL-based attribute
+    public void setItems(String items_) {
+        this.items_ = items_;
+    }
+
+    // for EL-based attribute
+    public void setDelims(String delims_) {
+	this.delims_ = delims_;
+    }
+
+
+    //*********************************************************************
+    // Private (utility) methods
+
+    // (re)initializes state (during release() or construction)
+    private void init() {
+        // defaults for interface with page author
+        begin_ = null;          // (no expression)
+        end_ = null;            // (no expression)
+        step_ = null;           // (no expression)
+	items_ = null;		// (no expression)
+	delims_ = null;		// (no expression)
+    }
+
+    /* Evaluates expressions as necessary */
+    private void evaluateExpressions() throws JspException {
+        /*
+         * Note: we don't check for type mismatches here; we assume
+         * the expression evaluator will return the expected type
+         * (by virtue of knowledge we give it about what that type is).
+         * A ClassCastException here is truly unexpected, so we let it
+         * propagate up.
+         */
+
+       if (begin_ != null) {
+            Object r = ExpressionEvaluatorManager.evaluate(
+                "begin", begin_, Integer.class, this, pageContext);
+            if (r == null)
+                throw new NullAttributeException("forTokens", "begin");
+            begin = ((Integer) r).intValue();
+            validateBegin();
+        }
+
+        if (end_ != null) {
+            Object r = ExpressionEvaluatorManager.evaluate(
+                "end", end_, Integer.class, this, pageContext);
+            if (r == null)
+                throw new NullAttributeException("forTokens", "end");
+            end = ((Integer) r).intValue();
+            validateEnd();
+        }
+
+        if (step_ != null) {
+            Object r = ExpressionEvaluatorManager.evaluate(
+                "step", step_, Integer.class, this, pageContext);
+            if (r == null)
+                throw new NullAttributeException("forTokens", "step");
+            step = ((Integer) r).intValue();
+            validateStep();
+        }
+
+        if (items_ != null) {
+            items = (String) ExpressionEvaluatorManager.evaluate(
+                "items", items_, String.class, this, pageContext);
+	    // use the empty string to indicate "no iteration"
+	    if (items == null)
+		items = "";
+	}
+
+        if (delims_ != null) {
+            delims = (String) ExpressionEvaluatorManager.evaluate(
+                "delims", delims_, String.class, this, pageContext);
+	    // use the empty string to cause monolithic tokenization
+	    if (delims == null)
+		delims = "";
+	}
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/el/core/IfTag.java b/standard/src/org/apache/taglibs/standard/tag/el/core/IfTag.java
new file mode 100644
index 0000000..7cc5fc9
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/el/core/IfTag.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.el.core;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.JspTagException;
+import javax.servlet.jsp.jstl.core.ConditionalTagSupport;
+
+import org.apache.taglibs.standard.lang.support.ExpressionEvaluatorManager;
+import org.apache.taglibs.standard.tag.common.core.NullAttributeException;
+
+/**
+ * <p>Tag handler for <if> in JSTL's expression-evaluating library.  
+ * Because of the support provided by the ConditionalTagSupport class,
+ * thistag is trivial enough not to require a separate base supporting
+ * class common to both libraries.</p>
+ *
+ * @author Shawn Bayern
+ */
+
+public class IfTag extends ConditionalTagSupport {
+
+    //*********************************************************************
+    // Constructor and lifecycle management
+
+    // initialize inherited and local state
+    public IfTag() {
+        super();
+        init();
+    }
+
+    // Releases any resources we may have (or inherit)
+    public void release() {
+        super.release();
+        init();
+    }
+
+
+    //*********************************************************************
+    // Supplied conditional logic
+
+    protected boolean condition() throws JspTagException {
+	try {
+            Object r = ExpressionEvaluatorManager.evaluate(
+                "test", test, Boolean.class, this, pageContext);
+            if (r == null)
+                throw new NullAttributeException("if", "test");
+	    else
+	        return (((Boolean) r).booleanValue());
+        } catch (JspException ex) {
+	    throw new JspTagException(ex.toString(), ex);
+	}
+    }
+
+
+    //*********************************************************************
+    // Private state
+
+    private String test;               // the value of the 'test' attribute
+
+
+    //*********************************************************************
+    // Accessors
+
+    // receives the tag's 'test' attribute
+    public void setTest(String test) {
+        this.test = test;
+    }
+
+
+    //*********************************************************************
+    // Private utility methods
+
+    // resets internal state
+    private void init() {
+        test = null;
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/el/core/ImportTag.java b/standard/src/org/apache/taglibs/standard/tag/el/core/ImportTag.java
new file mode 100644
index 0000000..2ba4061
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/el/core/ImportTag.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.el.core;
+
+import javax.servlet.jsp.JspException;
+
+import org.apache.taglibs.standard.tag.common.core.ImportSupport;
+import org.apache.taglibs.standard.tag.common.core.NullAttributeException;
+
+/**
+ * <p>A handler for <import> that accepts attributes as Strings
+ * and evaluates them as expressions at runtime.</p>
+ *
+ * @author Shawn Bayern
+ */
+
+public class ImportTag extends ImportSupport {
+
+    //*********************************************************************
+    // 'Private' state (implementation details)
+
+    private String context_;                    // stores EL-based property
+    private String charEncoding_;		// stores EL-based property
+    private String url_;			// stores EL-based property
+
+
+    //*********************************************************************
+    // Constructor
+
+    /**
+     * Constructs a new ImportTag.  As with TagSupport, subclasses
+     * should not provide other constructors and are expected to call
+     * the superclass constructor
+     */
+    public ImportTag() {
+        super();
+        init();
+    }
+
+
+    //*********************************************************************
+    // Tag logic
+
+    // evaluates expression and chains to parent
+    public int doStartTag() throws JspException {
+
+        // evaluate any expressions we were passed, once per invocation
+        evaluateExpressions();
+
+	// chain to the parent implementation
+	return super.doStartTag();
+    }
+
+
+    // Releases any resources we may have (or inherit)
+    public void release() {
+        super.release();
+        init();
+    }
+
+
+    //*********************************************************************
+    // Accessor methods
+
+    // for EL-based attribute
+    public void setUrl(String url_) {
+        this.url_ = url_;
+    }
+
+    public void setContext(String context_) {
+        this.context_ = context_;
+    }
+
+    public void setCharEncoding(String charEncoding_) {
+        this.charEncoding_ = charEncoding_;
+    }
+
+    //*********************************************************************
+    // Private (utility) methods
+
+    // (re)initializes state (during release() or construction)
+    private void init() {
+        // null implies "no expression"
+	url_ = context_ = charEncoding_ = null;
+    }
+
+    /* Evaluates expressions as necessary */
+    private void evaluateExpressions() throws JspException {
+        /* 
+         * Note: we don't check for type mismatches here; we assume
+         * the expression evaluator will return the expected type
+         * (by virtue of knowledge we give it about what that type is).
+         * A ClassCastException here is truly unexpected, so we let it
+         * propagate up.
+         */
+
+	url = (String) ExpressionUtil.evalNotNull(
+	    "import", "url", url_, String.class, this, pageContext);
+	if (url == null || url.equals(""))
+	    throw new NullAttributeException("import", "url");
+
+	context = (String) ExpressionUtil.evalNotNull(
+	    "import", "context", context_, String.class, this, pageContext);
+	charEncoding = (String) ExpressionUtil.evalNotNull(
+	    "import", "charEncoding", charEncoding_, String.class, this,
+	    pageContext);
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/el/core/OutTag.java b/standard/src/org/apache/taglibs/standard/tag/el/core/OutTag.java
new file mode 100644
index 0000000..226c9cc
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/el/core/OutTag.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.el.core;
+
+import javax.servlet.jsp.JspException;
+
+import org.apache.taglibs.standard.tag.common.core.NullAttributeException;
+import org.apache.taglibs.standard.tag.common.core.OutSupport;
+
+/**
+ * <p>A handler for <out>, which redirects the browser to a
+ * new URL.
+ *
+ * @author Shawn Bayern
+ */
+
+public class OutTag extends OutSupport {
+
+    //*********************************************************************
+    // 'Private' state (implementation details)
+
+    private String value_;			// stores EL-based property
+    private String default_;			// stores EL-based property
+    private String escapeXml_;			// stores EL-based property
+
+
+    //*********************************************************************
+    // Constructor
+
+    public OutTag() {
+        super();
+        init();
+    }
+
+
+    //*********************************************************************
+    // Tag logic
+
+    // evaluates expression and chains to parent
+    public int doStartTag() throws JspException {
+
+        // evaluate any expressions we were passed, once per invocation
+        evaluateExpressions();
+
+	// chain to the parent implementation
+	return super.doStartTag();
+    }
+
+
+    // Releases any resources we may have (or inherit)
+    public void release() {
+        super.release();
+        init();
+    }
+
+
+    //*********************************************************************
+    // Accessor methods
+
+    public void setValue(String value_) {
+        this.value_ = value_;
+    }
+
+    public void setDefault(String default_) {
+        this.default_ = default_;
+    }
+
+    public void setEscapeXml(String escapeXml_) {
+        this.escapeXml_ = escapeXml_;
+    }
+
+
+    //*********************************************************************
+    // Private (utility) methods
+
+    // (re)initializes state (during release() or construction)
+    private void init() {
+        // null implies "no expression"
+	value_ = default_ = escapeXml_ = null;
+    }
+
+    /* Evaluates expressions as necessary */
+    private void evaluateExpressions() throws JspException {
+	try {
+	    value = ExpressionUtil.evalNotNull(
+	        "out", "value", value_, Object.class, this, pageContext);
+	} catch (NullAttributeException ex) {
+	    // explicitly allow 'null' for value
+	    value = null;
+	}
+	try { 
+	    def = (String) ExpressionUtil.evalNotNull(
+	        "out", "default", default_, String.class, this, pageContext);
+	} catch (NullAttributeException ex) {
+	    // explicitly allow 'null' for def
+	    def = null;
+	}
+	escapeXml = true;
+	Boolean escape = ((Boolean) ExpressionUtil.evalNotNull(
+	    "out", "escapeXml", escapeXml_, Boolean.class, this, pageContext));
+	if (escape != null)
+	    escapeXml = escape.booleanValue();
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/el/core/ParamTag.java b/standard/src/org/apache/taglibs/standard/tag/el/core/ParamTag.java
new file mode 100644
index 0000000..0e01113
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/el/core/ParamTag.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.el.core;
+
+import javax.servlet.jsp.JspException;
+
+import org.apache.taglibs.standard.tag.common.core.ParamSupport;
+
+/**
+ * <p>A handler for <param> that accepts attributes as Strings
+ * and evaluates them as expressions at runtime.</p>
+ *
+ * @author Shawn Bayern
+ */
+
+public class ParamTag extends ParamSupport {
+
+    //*********************************************************************
+    // 'Private' state (implementation details)
+
+    private String name_;                       // stores EL-based property
+    private String value_;			// stores EL-based property
+
+
+    //*********************************************************************
+    // Constructor
+
+    /**
+     * Constructs a new ParamTag.  As with TagSupport, subclasses
+     * should not provide other constructors and are expected to call
+     * the superclass constructor
+     */
+    public ParamTag() {
+        super();
+        init();
+    }
+
+
+    //*********************************************************************
+    // Tag logic
+
+    // evaluates expression and chains to parent
+    public int doStartTag() throws JspException {
+
+        // evaluate any expressions we were passed, once per invocation
+        evaluateExpressions();
+
+	// chain to the parent implementation
+	return super.doStartTag();
+    }
+
+
+    // Releases any resources we may have (or inherit)
+    public void release() {
+        super.release();
+        init();
+    }
+
+
+    //*********************************************************************
+    // Accessor methods
+
+    // for EL-based attribute
+    public void setName(String name_) {
+        this.name_ = name_;
+    }
+
+    public void setValue(String value_) {
+        this.value_ = value_;
+    }
+
+
+    //*********************************************************************
+    // Private (utility) methods
+
+    // (re)initializes state (during release() or construction)
+    private void init() {
+        // null implies "no expression"
+	name_ = value_ = null;
+    }
+
+    /* Evaluates expressions as necessary */
+    private void evaluateExpressions() throws JspException {
+        /* 
+         * Note: we don't check for type mismatches here; we assume
+         * the expression evaluator will return the expected type
+         * (by virtue of knowledge we give it about what that type is).
+         * A ClassCastException here is truly unexpected, so we let it
+         * propagate up.
+         */
+
+	name = (String) ExpressionUtil.evalNotNull(
+	    "import", "name", name_, String.class, this, pageContext);
+	value = (String) ExpressionUtil.evalNotNull(
+	    "import", "value", value_, String.class, this, pageContext);
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/el/core/RedirectTag.java b/standard/src/org/apache/taglibs/standard/tag/el/core/RedirectTag.java
new file mode 100644
index 0000000..21078d5
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/el/core/RedirectTag.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.el.core;
+
+import javax.servlet.jsp.JspException;
+
+import org.apache.taglibs.standard.tag.common.core.RedirectSupport;
+
+/**
+ * <p>A handler for <redirect>, which redirects the browser to a
+ * new URL.
+ *
+ * @author Shawn Bayern
+ */
+
+public class RedirectTag extends RedirectSupport {
+
+    //*********************************************************************
+    // 'Private' state (implementation details)
+
+    private String url_;			// stores EL-based property
+    private String context_;			// stores EL-based property
+
+
+    //*********************************************************************
+    // Constructor
+
+    /**
+     * Constructs a new URLEncodeTag.  As with TagSupport, subclasses
+     * should not provide other constructors and are expected to call
+     * the superclass constructor
+     */
+    public RedirectTag() {
+        super();
+        init();
+    }
+
+
+    //*********************************************************************
+    // Tag logic
+
+    // evaluates expression and chains to parent
+    public int doStartTag() throws JspException {
+
+        // evaluate any expressions we were passed, once per invocation
+        evaluateExpressions();
+
+	// chain to the parent implementation
+	return super.doStartTag();
+    }
+
+
+    // Releases any resources we may have (or inherit)
+    public void release() {
+        super.release();
+        init();
+    }
+
+
+    //*********************************************************************
+    // Accessor methods
+
+    public void setUrl(String url_) {
+        this.url_ = url_;
+    }
+
+    public void setContext(String context_) {
+        this.context_ = context_;
+    }
+
+    //*********************************************************************
+    // Private (utility) methods
+
+    // (re)initializes state (during release() or construction)
+    private void init() {
+        // null implies "no expression"
+	url_ = context_ = null;
+    }
+
+    /* Evaluates expressions as necessary */
+    private void evaluateExpressions() throws JspException {
+        /* 
+         * Note: we don't check for type mismatches here; we assume
+         * the expression evaluator will return the expected type
+         * (by virtue of knowledge we give it about what that type is).
+         * A ClassCastException here is truly unexpected, so we let it
+         * propagate up.
+         */
+
+	url = (String) ExpressionUtil.evalNotNull(
+	    "redirect", "url", url_, String.class, this, pageContext);
+	context = (String) ExpressionUtil.evalNotNull(
+	    "redirect", "context", context_, String.class, this, pageContext);
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/el/core/SetTag.java b/standard/src/org/apache/taglibs/standard/tag/el/core/SetTag.java
new file mode 100644
index 0000000..9f52289
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/el/core/SetTag.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.el.core;
+
+import javax.servlet.jsp.JspException;
+
+import org.apache.taglibs.standard.tag.common.core.NullAttributeException;
+import org.apache.taglibs.standard.tag.common.core.SetSupport;
+
+/**
+ * <p>A handler for <set>, which redirects the browser to a
+ * new URL.
+ *
+ * @author Shawn Bayern
+ */
+
+public class SetTag extends SetSupport {
+
+    //*********************************************************************
+    // 'Private' state (implementation details)
+
+    private String value_;			// stores EL-based property
+    private String target_;			// stores EL-based property
+    private String property_;			// stores EL-based property
+
+
+    //*********************************************************************
+    // Constructor
+
+    public SetTag() {
+        super();
+        init();
+    }
+
+
+    //*********************************************************************
+    // Tag logic
+
+    // evaluates expression and chains to parent
+    public int doStartTag() throws JspException {
+
+        // evaluate any expressions we were passed, once per invocation
+        evaluateExpressions();
+
+	// chain to the parent implementation
+	return super.doStartTag();
+    }
+
+
+    // Releases any resources we may have (or inherit)
+    public void release() {
+        super.release();
+        init();
+    }
+
+
+    //*********************************************************************
+    // Accessor methods
+
+    public void setValue(String value_) {
+        this.value_ = value_;
+	this.valueSpecified = true;
+    }
+
+    public void setTarget(String target_) {
+        this.target_ = target_;
+    }
+
+    public void setProperty(String property_) {
+        this.property_ = property_;
+    }
+
+
+    //*********************************************************************
+    // Private (utility) methods
+
+    // (re)initializes state (during release() or construction)
+    private void init() {
+        // null implies "no expression"
+	value_ = target_ = property_ = null;
+    }
+
+    /* Evaluates expressions as necessary */
+    private void evaluateExpressions() throws JspException {
+        /* 
+         * Note: we don't check for type mismatches here; we assume
+         * the expression evaluator will return the expected type
+         * (by virtue of knowledge we give it about what that type is).
+         * A ClassCastException here is truly unexpected, so we let it
+         * propagate up.
+         */
+
+	// 'value'
+	try {
+	    value = ExpressionUtil.evalNotNull(
+	        "set", "value", value_, Object.class, this, pageContext);
+	} catch (NullAttributeException ex) {
+	    // explicitly let 'value' be null
+	    value = null;
+	}
+
+	// 'target'
+	target = ExpressionUtil.evalNotNull(
+	    "set", "target", target_, Object.class, this, pageContext);
+
+	// 'property'
+	try {
+	    property = (String) ExpressionUtil.evalNotNull(
+	         "set", "property", property_, String.class, this, pageContext);
+        } catch (NullAttributeException ex) {
+            // explicitly let 'property' be null
+            property = null;
+        }
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/el/core/UrlTag.java b/standard/src/org/apache/taglibs/standard/tag/el/core/UrlTag.java
new file mode 100644
index 0000000..f65405c
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/el/core/UrlTag.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.el.core;
+
+import javax.servlet.jsp.JspException;
+
+import org.apache.taglibs.standard.tag.common.core.UrlSupport;
+
+/**
+ * <p>A handler for <urlEncode> that accepts attributes as Strings
+ * and evaluates them as expressions at runtime.</p>
+ *
+ * @author Shawn Bayern
+ */
+
+public class UrlTag extends UrlSupport {
+
+    //*********************************************************************
+    // 'Private' state (implementation details)
+
+    private String value_;			// stores EL-based property
+    private String context_;			// stores EL-based property
+
+
+    //*********************************************************************
+    // Constructor
+
+    /**
+     * Constructs a new URLEncodeTag.  As with TagSupport, subclasses
+     * should not provide other constructors and are expected to call
+     * the superclass constructor
+     */
+    public UrlTag() {
+        super();
+        init();
+    }
+
+
+    //*********************************************************************
+    // Tag logic
+
+    // evaluates expression and chains to parent
+    public int doStartTag() throws JspException {
+
+        // evaluate any expressions we were passed, once per invocation
+        evaluateExpressions();
+
+	// chain to the parent implementation
+	return super.doStartTag();
+    }
+
+
+    // Releases any resources we may have (or inherit)
+    public void release() {
+        super.release();
+        init();
+    }
+
+
+    //*********************************************************************
+    // Accessor methods
+
+    public void setValue(String value_) {
+        this.value_ = value_;
+    }
+
+    public void setContext(String context_) {
+        this.context_ = context_;
+    }
+
+
+    //*********************************************************************
+    // Private (utility) methods
+
+    // (re)initializes state (during release() or construction)
+    private void init() {
+        // null implies "no expression"
+	value_ = null;
+    }
+
+    /* Evaluates expressions as necessary */
+    private void evaluateExpressions() throws JspException {
+        /* 
+         * Note: we don't check for type mismatches here; we assume
+         * the expression evaluator will return the expected type
+         * (by virtue of knowledge we give it about what that type is).
+         * A ClassCastException here is truly unexpected, so we let it
+         * propagate up.
+         */
+
+	value = (String) ExpressionUtil.evalNotNull(
+	    "url", "value", value_, String.class, this, pageContext);
+	context = (String) ExpressionUtil.evalNotNull(
+	    "url", "context", context_, String.class, this, pageContext);
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/el/core/WhenTag.java b/standard/src/org/apache/taglibs/standard/tag/el/core/WhenTag.java
new file mode 100644
index 0000000..545d63d
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/el/core/WhenTag.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.el.core;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.JspTagException;
+
+import org.apache.taglibs.standard.lang.support.ExpressionEvaluatorManager;
+import org.apache.taglibs.standard.tag.common.core.NullAttributeException;
+import org.apache.taglibs.standard.tag.common.core.WhenTagSupport;
+
+/**
+ * <p>Tag handler for <when> in JSTL's expression-evaluating
+ * library.</p>
+ *
+ * @author Shawn Bayern
+ */
+
+public class WhenTag extends WhenTagSupport {
+
+    //*********************************************************************
+    // Constructor and lifecycle management
+
+    // initialize inherited and local state
+    public WhenTag() {
+        super();
+        init();
+    }
+
+    // Releases any resources we may have (or inherit)
+    public void release() {
+        super.release();
+        init();
+    }
+
+
+    //*********************************************************************
+    // Supplied conditional logic
+
+    protected boolean condition() throws JspTagException {
+        try { 
+            Object r = ExpressionEvaluatorManager.evaluate(
+                "test", test, Boolean.class, this, pageContext);
+            if (r == null)
+	        throw new NullAttributeException("when", "test");
+            else
+                return (((Boolean) r).booleanValue());
+	} catch (JspException ex) {
+	    throw new JspTagException(ex.toString(), ex);
+	}
+    }
+
+
+    //*********************************************************************
+    // Private state
+
+    private String test;               // the value of the 'test' attribute
+
+
+    //*********************************************************************
+    // Accessors
+
+    // receives the tag's 'test' attribute
+    public void setTest(String test) {
+        this.test = test;
+    }
+
+
+    //*********************************************************************
+    // Private utility methods
+
+    // resets internal state
+    private void init() {
+        test = null;
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/el/fmt/BundleTag.java b/standard/src/org/apache/taglibs/standard/tag/el/fmt/BundleTag.java
new file mode 100644
index 0000000..fc97f7e
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/el/fmt/BundleTag.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.el.fmt;
+
+import javax.servlet.jsp.JspException;
+
+import org.apache.taglibs.standard.lang.support.ExpressionEvaluatorManager;
+import org.apache.taglibs.standard.tag.common.fmt.BundleSupport;
+
+/**
+ * <p>A handler for <bundle> that accepts attributes as Strings
+ * and evaluates them as expressions at runtime.</p>
+ *
+ * @author Shawn Bayern
+ * @author Jan Luehe
+ */
+
+public class BundleTag extends BundleSupport {
+
+    //*********************************************************************
+    // 'Private' state (implementation details)
+
+    private String basename_;                    // stores EL-based property
+    private String prefix_;		         // stores EL-based property
+
+
+    //*********************************************************************
+    // Constructor
+
+    /**
+     * Constructs a new BundleTag.  As with TagSupport, subclasses
+     * should not provide other constructors and are expected to call
+     * the superclass constructor
+     */
+    public BundleTag() {
+        super();
+        init();
+    }
+
+
+    //*********************************************************************
+    // Tag logic
+
+    // evaluates expression and chains to parent
+    public int doStartTag() throws JspException {
+
+        // evaluate any expressions we were passed, once per invocation
+        evaluateExpressions();
+
+	// chain to the parent implementation
+	return super.doStartTag();
+    }
+
+    // Releases any resources we may have (or inherit)
+    public void release() {
+        super.release();
+        init();
+    }
+
+
+    //*********************************************************************
+    // Accessor methods
+
+    // for EL-based attribute
+    public void setBasename(String basename_) {
+        this.basename_ = basename_;
+    }
+
+    // for EL-based attribute
+    public void setPrefix(String prefix_) {
+        this.prefix_ = prefix_;
+    }
+
+
+    //*********************************************************************
+    // Private (utility) methods
+
+    // (re)initializes state (during release() or construction)
+    private void init() {
+        // null implies "no expression"
+	basename_ = prefix_ = null;
+    }
+
+    // Evaluates expressions as necessary
+    private void evaluateExpressions() throws JspException {
+
+	// 'basename' attribute (mandatory)
+	basename = (String) ExpressionEvaluatorManager.evaluate(
+	    "basename", basename_, String.class, this, pageContext);
+
+	// 'prefix' attribute (optional)
+	if (prefix_ != null) {
+	    prefix = (String) ExpressionEvaluatorManager.evaluate(
+	        "prefix", prefix_, String.class, this, pageContext);
+	}
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/el/fmt/FormatDateTag.java b/standard/src/org/apache/taglibs/standard/tag/el/fmt/FormatDateTag.java
new file mode 100644
index 0000000..de3cef0
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/el/fmt/FormatDateTag.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.el.fmt;
+
+import java.util.Date;
+
+import javax.servlet.jsp.JspException;
+
+import org.apache.taglibs.standard.lang.support.ExpressionEvaluatorManager;
+import org.apache.taglibs.standard.tag.common.fmt.FormatDateSupport;
+
+/**
+ * <p>A handler for <formatDate> that accepts attributes as Strings
+ * and evaluates them as expressions at runtime.</p>
+ *
+ * @author Jan Luehe
+ */
+
+public class FormatDateTag extends FormatDateSupport {
+
+    //*********************************************************************
+    // 'Private' state (implementation details)
+
+    private String value_;                       // stores EL-based property
+    private String type_;                        // stores EL-based property
+    private String dateStyle_;		         // stores EL-based property
+    private String timeStyle_;		         // stores EL-based property
+    private String pattern_;		         // stores EL-based property
+    private String timeZone_;		         // stores EL-based property
+
+
+    //*********************************************************************
+    // Constructor
+
+    /**
+     * Constructs a new FormatDateTag.  As with TagSupport, subclasses
+     * should not provide other constructors and are expected to call
+     * the superclass constructor
+     */
+    public FormatDateTag() {
+        super();
+        init();
+    }
+
+
+    //*********************************************************************
+    // Tag logic
+
+    // evaluates expression and chains to parent
+    public int doStartTag() throws JspException {
+
+        // evaluate any expressions we were passed, once per invocation
+        evaluateExpressions();
+
+	// chain to the parent implementation
+	return super.doStartTag();
+    }
+
+    // Releases any resources we may have (or inherit)
+    public void release() {
+        super.release();
+        init();
+    }
+
+
+    //*********************************************************************
+    // Accessor methods
+
+    // for EL-based attribute
+    public void setValue(String value_) {
+        this.value_ = value_;
+    }
+
+    // for EL-based attribute
+    public void setType(String type_) {
+        this.type_ = type_;
+    }
+
+    // for EL-based attribute
+    public void setDateStyle(String dateStyle_) {
+        this.dateStyle_ = dateStyle_;
+    }
+
+    // for EL-based attribute
+    public void setTimeStyle(String timeStyle_) {
+        this.timeStyle_ = timeStyle_;
+    }
+
+    // for EL-based attribute
+    public void setPattern(String pattern_) {
+        this.pattern_ = pattern_;
+    }
+
+    // for EL-based attribute
+    public void setTimeZone(String timeZone_) {
+        this.timeZone_ = timeZone_;
+    }
+
+
+    //*********************************************************************
+    // Private (utility) methods
+
+    // (re)initializes state (during release() or construction)
+    private void init() {
+        // null implies "no expression"
+	value_ = type_ = dateStyle_ = timeStyle_ = pattern_ = timeZone_ = null;
+    }
+
+    // Evaluates expressions as necessary
+    private void evaluateExpressions() throws JspException {
+        /* 
+         * Note: we don't check for type mismatches here; we assume
+         * the expression evaluator will return the expected type
+         * (by virtue of knowledge we give it about what that type is).
+         * A ClassCastException here is truly unexpected, so we let it
+         * propagate up.
+         */
+
+	// 'value' attribute (mandatory)
+	value = (Date) ExpressionEvaluatorManager.evaluate(
+	    "value", value_, Date.class, this, pageContext);
+
+	// 'type' attribute
+	if (type_ != null) {
+	    type = (String) ExpressionEvaluatorManager.evaluate(
+	        "type", type_, String.class, this, pageContext);
+	}
+
+	// 'dateStyle' attribute
+	if (dateStyle_ != null) {
+	    dateStyle = (String) ExpressionEvaluatorManager.evaluate(
+	        "dateStyle", dateStyle_, String.class, this, pageContext);
+	}
+
+	// 'timeStyle' attribute
+	if (timeStyle_ != null) {
+	    timeStyle = (String) ExpressionEvaluatorManager.evaluate(
+	        "timeStyle", timeStyle_, String.class, this, pageContext);
+	}
+
+	// 'pattern' attribute
+	if (pattern_ != null) {
+	    pattern = (String) ExpressionEvaluatorManager.evaluate(
+	        "pattern", pattern_, String.class, this, pageContext);
+	}
+
+	// 'timeZone' attribute
+	if (timeZone_ != null) {
+	    timeZone = ExpressionEvaluatorManager.evaluate(
+	        "timeZone", timeZone_, Object.class, this, pageContext);
+	}
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/el/fmt/FormatNumberTag.java b/standard/src/org/apache/taglibs/standard/tag/el/fmt/FormatNumberTag.java
new file mode 100644
index 0000000..e7f736e
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/el/fmt/FormatNumberTag.java
@@ -0,0 +1,250 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.el.fmt;
+
+import javax.servlet.jsp.JspException;
+
+import org.apache.taglibs.standard.lang.support.ExpressionEvaluatorManager;
+import org.apache.taglibs.standard.tag.common.fmt.FormatNumberSupport;
+
+/**
+ * <p>A handler for <formatNumber> that accepts attributes as Strings
+ * and evaluates them as expressions at runtime.</p>
+ *
+ * @author Jan Luehe
+ */
+
+public class FormatNumberTag extends FormatNumberSupport {
+
+    //*********************************************************************
+    // 'Private' state (implementation details)
+
+    private String value_;                       // stores EL-based property
+    private String type_;                        // stores EL-based property
+    private String pattern_;		         // stores EL-based property
+    private String currencyCode_;   	         // stores EL-based property
+    private String currencySymbol_;   	         // stores EL-based property
+    private String groupingUsed_;   	         // stores EL-based property
+    private String maxIntegerDigits_;   	 // stores EL-based property
+    private String minIntegerDigits_;   	 // stores EL-based property
+    private String maxFractionDigits_;   	 // stores EL-based property
+    private String minFractionDigits_;   	 // stores EL-based property
+
+
+    //*********************************************************************
+    // Constructor
+
+    /**
+     * Constructs a new FormatNumberTag.  As with TagSupport, subclasses
+     * should not provide other constructors and are expected to call
+     * the superclass constructor
+     */
+    public FormatNumberTag() {
+        super();
+        init();
+    }
+
+
+    //*********************************************************************
+    // Tag logic
+
+    // evaluates expression and chains to parent
+    public int doStartTag() throws JspException {
+
+        // evaluate any expressions we were passed, once per invocation
+        evaluateExpressions();
+
+	// chain to the parent implementation
+	return super.doStartTag();
+    }
+
+    // Releases any resources we may have (or inherit)
+    public void release() {
+        super.release();
+        init();
+    }
+
+
+    //*********************************************************************
+    // Accessor methods
+
+    // for EL-based attribute
+    public void setValue(String value_) {
+        this.value_ = value_;
+	this.valueSpecified = true;
+    }
+
+    // for EL-based attribute
+    public void setType(String type_) {
+        this.type_ = type_;
+    }
+
+    // for EL-based attribute
+    public void setPattern(String pattern_) {
+        this.pattern_ = pattern_;
+    }
+
+    // for EL-based attribute
+    public void setCurrencyCode(String currencyCode_) {
+        this.currencyCode_ = currencyCode_;
+    }
+
+    // for EL-based attribute
+    public void setCurrencySymbol(String currencySymbol_) {
+        this.currencySymbol_ = currencySymbol_;
+    }
+
+    // for EL-based attribute
+    public void setGroupingUsed(String groupingUsed_) {
+        this.groupingUsed_ = groupingUsed_;
+	this.groupingUsedSpecified = true;
+    }
+
+    // for EL-based attribute
+    public void setMaxIntegerDigits(String maxIntegerDigits_) {
+        this.maxIntegerDigits_ = maxIntegerDigits_;
+	this.maxIntegerDigitsSpecified = true;
+    }
+
+    // for EL-based attribute
+    public void setMinIntegerDigits(String minIntegerDigits_) {
+        this.minIntegerDigits_ = minIntegerDigits_;
+	this.minIntegerDigitsSpecified = true;
+    }
+
+    // for EL-based attribute
+    public void setMaxFractionDigits(String maxFractionDigits_) {
+        this.maxFractionDigits_ = maxFractionDigits_;
+	this.maxFractionDigitsSpecified = true;
+    }
+
+    // for EL-based attribute
+    public void setMinFractionDigits(String minFractionDigits_) {
+        this.minFractionDigits_ = minFractionDigits_;
+	this.minFractionDigitsSpecified = true;
+    }
+
+
+    //*********************************************************************
+    // Private (utility) methods
+
+    // (re)initializes state (during release() or construction)
+    private void init() {
+        // null implies "no expression"
+	value_ = type_ = pattern_ = null;
+	currencyCode_ = currencySymbol_ = null;
+	groupingUsed_ = null;
+	maxIntegerDigits_ = minIntegerDigits_ = null;
+	maxFractionDigits_ = minFractionDigits_ = null;
+    }
+
+    // Evaluates expressions as necessary
+    private void evaluateExpressions() throws JspException {
+	Object obj = null;
+
+        /* 
+         * Note: we don't check for type mismatches here; we assume
+         * the expression evaluator will return the expected type
+         * (by virtue of knowledge we give it about what that type is).
+         * A ClassCastException here is truly unexpected, so we let it
+         * propagate up.
+         */
+
+	// 'value' attribute
+	if (value_ != null) {
+	    value = ExpressionEvaluatorManager.evaluate(
+	        "value", value_, Object.class, this, pageContext);
+	}
+
+	// 'type' attribute
+	if (type_ != null) {
+	    type = (String) ExpressionEvaluatorManager.evaluate(
+	        "type", type_, String.class, this, pageContext);
+	}
+
+	// 'pattern' attribute
+	if (pattern_ != null) {
+	    pattern = (String) ExpressionEvaluatorManager.evaluate(
+	        "pattern", pattern_, String.class, this, pageContext);
+	}
+
+	// 'currencyCode' attribute
+	if (currencyCode_ != null) {
+	    currencyCode = (String) ExpressionEvaluatorManager.evaluate(
+	        "currencyCode", currencyCode_, String.class, this,
+		pageContext);
+	}
+
+	// 'currencySymbol' attribute
+	if (currencySymbol_ != null) {
+	    currencySymbol = (String) ExpressionEvaluatorManager.evaluate(
+	        "currencySymbol", currencySymbol_, String.class, this,
+		pageContext);
+	}
+
+	// 'groupingUsed' attribute
+	if (groupingUsed_ != null) {
+	    obj = ExpressionEvaluatorManager.evaluate(
+	        "groupingUsed", groupingUsed_, Boolean.class, this,
+		pageContext);
+	    if (obj != null) {
+		isGroupingUsed = ((Boolean) obj).booleanValue();
+	    }
+	}
+
+	// 'maxIntegerDigits' attribute
+	if (maxIntegerDigits_ != null) {
+	    obj = ExpressionEvaluatorManager.evaluate(
+	        "maxIntegerDigits", maxIntegerDigits_, Integer.class, this,
+		pageContext);
+	    if (obj != null) {
+		maxIntegerDigits = ((Integer) obj).intValue();
+	    }
+	}
+
+	// 'minIntegerDigits' attribute	
+	if (minIntegerDigits_ != null) {
+	    obj = ExpressionEvaluatorManager.evaluate(
+	        "minIntegerDigits", minIntegerDigits_, Integer.class, this,
+		pageContext);
+	    if (obj != null) {
+		minIntegerDigits = ((Integer) obj).intValue();
+	    }
+	}
+
+	// 'maxFractionDigits' attribute
+	if (maxFractionDigits_ != null) {
+	    obj = ExpressionEvaluatorManager.evaluate(
+	        "maxFractionDigits", maxFractionDigits_, Integer.class, this,
+		pageContext);
+	    if (obj != null) {
+		maxFractionDigits = ((Integer) obj).intValue();
+	    }
+	}
+
+	// 'minFractionDigits' attribute
+	if (minFractionDigits_ != null) {
+	    obj = ExpressionEvaluatorManager.evaluate(
+	        "minFractionDigits", minFractionDigits_, Integer.class, this,
+		pageContext);
+	    if (obj != null) {
+		minFractionDigits = ((Integer) obj).intValue();
+	    }
+	}
+    }
+}
+
diff --git a/standard/src/org/apache/taglibs/standard/tag/el/fmt/MessageTag.java b/standard/src/org/apache/taglibs/standard/tag/el/fmt/MessageTag.java
new file mode 100644
index 0000000..716efe0
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/el/fmt/MessageTag.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.el.fmt;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.jstl.fmt.LocalizationContext;
+
+import org.apache.taglibs.standard.lang.support.ExpressionEvaluatorManager;
+import org.apache.taglibs.standard.tag.common.fmt.MessageSupport;
+
+/**
+ * <p>A handler for <message> that accepts attributes as Strings
+ * and evaluates them as expressions at runtime.</p>
+ *
+ * @author Jan Luehe
+ */
+
+public class MessageTag extends MessageSupport {
+
+    //*********************************************************************
+    // Private state (implementation details)
+
+    private String key_;                         // stores EL-based property
+    private String bundle_;		         // stores EL-based property
+
+
+    //*********************************************************************
+    // Constructor
+
+    /**
+     * Constructs a new MessageTag.  As with TagSupport, subclasses
+     * should not provide other constructors and are expected to call
+     * the superclass constructor
+     */
+    public MessageTag() {
+        super();
+        init();
+    }
+
+
+    //*********************************************************************
+    // Tag logic
+
+    // evaluates expression and chains to parent
+    public int doStartTag() throws JspException {
+
+        // evaluate any expressions we were passed, once per invocation
+        evaluateExpressions();
+
+	// chain to the parent implementation
+	return super.doStartTag();
+    }
+
+    // Releases any resources we may have (or inherit)
+    public void release() {
+        super.release();
+        init();
+    }
+
+
+    //*********************************************************************
+    // Accessor methods
+
+    // for EL-based attribute
+    public void setKey(String key_) {
+        this.key_ = key_;
+	this.keySpecified = true;
+    }
+
+    // for EL-based attribute
+    public void setBundle(String bundle_) {
+        this.bundle_ = bundle_;
+        this.bundleSpecified = true;
+    }
+
+
+    //*********************************************************************
+    // Private (utility) methods
+
+    // (re)initializes state (during release() or construction)
+    private void init() {
+        // null implies "no expression"
+	key_ = bundle_ = null;
+    }
+
+    // Evaluates expressions as necessary
+    private void evaluateExpressions() throws JspException {
+        /* 
+         * Note: we don't check for type mismatches here; we assume
+         * the expression evaluator will return the expected type
+         * (by virtue of knowledge we give it about what that type is).
+         * A ClassCastException here is truly unexpected, so we let it
+         * propagate up.
+         */
+
+	if (keySpecified) {
+	    keyAttrValue = (String) ExpressionEvaluatorManager.evaluate(
+	        "key", key_, String.class, this, pageContext);
+	}
+
+	if (bundleSpecified) {
+	    bundleAttrValue = (LocalizationContext)
+		ExpressionEvaluatorManager.evaluate(
+	            "bundle", bundle_, LocalizationContext.class, this,
+		    pageContext);
+	} 
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/el/fmt/ParamTag.java b/standard/src/org/apache/taglibs/standard/tag/el/fmt/ParamTag.java
new file mode 100644
index 0000000..efa7cf2
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/el/fmt/ParamTag.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.el.fmt;
+
+import javax.servlet.jsp.JspException;
+
+import org.apache.taglibs.standard.lang.support.ExpressionEvaluatorManager;
+import org.apache.taglibs.standard.tag.common.fmt.ParamSupport;
+
+/**
+ * <p>A handler for <param> that accepts message arguments as
+ * Strings and evaluates them as expressions at runtime.</p>
+ *
+ * @author Jan Luehe
+ */
+
+public class ParamTag extends ParamSupport {
+
+    //*********************************************************************
+    // 'Private' state (implementation details)
+
+    private String value_;                    // stores EL-based property
+
+
+    //*********************************************************************
+    // Constructor
+
+    /**
+     * Constructs a new ParamTag.  As with TagSupport, subclasses
+     * should not provide other constructors and are expected to call
+     * the superclass constructor
+     */
+    public ParamTag() {
+        super();
+        init();
+    }
+
+
+    //*********************************************************************
+    // Tag logic
+
+    // evaluates expression and chains to parent
+    public int doStartTag() throws JspException {
+
+        // evaluate any expressions we were passed, once per invocation
+        evaluateExpressions();
+
+	// chain to the parent implementation
+	return super.doStartTag();
+    }
+
+    // Releases any resources we may have (or inherit)
+    public void release() {
+        super.release();
+        init();
+    }
+
+
+    //*********************************************************************
+    // Accessor methods
+
+    // for EL-based attribute
+    public void setValue(String value_) {
+        this.value_ = value_;
+	this.valueSpecified = true;
+    }
+
+
+    //*********************************************************************
+    // Private (utility) methods
+
+    // (re)initializes state (during release() or construction)
+    private void init() {
+        // null implies "no expression"
+	value_ = null;
+    }
+
+    // Evaluates expressions as necessary
+    private void evaluateExpressions() throws JspException {
+        /* 
+         * Note: we don't check for type mismatches here; we assume
+         * the expression evaluator will return the expected type
+         * (by virtue of knowledge we give it about what that type is).
+         * A ClassCastException here is truly unexpected, so we let it
+         * propagate up.
+         */
+
+	if (value_ != null) {
+	    value = ExpressionEvaluatorManager.evaluate(
+	        "value", value_, Object.class, this, pageContext);
+	}
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/el/fmt/ParseDateTag.java b/standard/src/org/apache/taglibs/standard/tag/el/fmt/ParseDateTag.java
new file mode 100644
index 0000000..12bb982
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/el/fmt/ParseDateTag.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.el.fmt;
+
+import java.util.Locale;
+
+import javax.servlet.jsp.JspException;
+
+import org.apache.taglibs.standard.lang.support.ExpressionEvaluatorManager;
+import org.apache.taglibs.standard.tag.common.fmt.ParseDateSupport;
+import org.apache.taglibs.standard.tag.common.fmt.SetLocaleSupport;
+
+/**
+ * <p>A handler for <parseDate> that accepts attributes as Strings
+ * and evaluates them as expressions at runtime.</p>
+ *
+ * @author Jan Luehe
+ */
+
+public class ParseDateTag extends ParseDateSupport {
+
+    //*********************************************************************
+    // 'Private' state (implementation details)
+
+    private String value_;                       // stores EL-based property
+    private String type_;                        // stores EL-based property
+    private String dateStyle_;		         // stores EL-based property
+    private String timeStyle_;		         // stores EL-based property
+    private String pattern_;		         // stores EL-based property
+    private String timeZone_;		         // stores EL-based property
+    private String parseLocale_;	         // stores EL-based property
+
+
+    //*********************************************************************
+    // Constructor
+
+    /**
+     * Constructs a new ParseDateTag.  As with TagSupport, subclasses
+     * should not provide other constructors and are expected to call
+     * the superclass constructor
+     */
+    public ParseDateTag() {
+        super();
+        init();
+    }
+
+
+    //*********************************************************************
+    // Tag logic
+
+    // evaluates expression and chains to parent
+    public int doStartTag() throws JspException {
+
+        // evaluate any expressions we were passed, once per invocation
+        evaluateExpressions();
+
+	// chain to the parent implementation
+	return super.doStartTag();
+    }
+
+    // Releases any resources we may have (or inherit)
+    public void release() {
+        super.release();
+        init();
+    }
+
+
+    //*********************************************************************
+    // Accessor methods
+
+    // for EL-based attribute
+    public void setValue(String value_) {
+        this.value_ = value_;
+	this.valueSpecified = true;
+    }
+
+    // for EL-based attribute
+    public void setType(String type_) {
+        this.type_ = type_;
+    }
+
+    // for EL-based attribute
+    public void setDateStyle(String dateStyle_) {
+        this.dateStyle_ = dateStyle_;
+    }
+
+    // for EL-based attribute
+    public void setTimeStyle(String timeStyle_) {
+        this.timeStyle_ = timeStyle_;
+    }
+
+    // for EL-based attribute
+    public void setPattern(String pattern_) {
+        this.pattern_ = pattern_;
+    }
+
+    // for EL-based attribute
+    public void setTimeZone(String timeZone_) {
+        this.timeZone_ = timeZone_;
+    }
+
+    // for EL-based attribute
+    public void setParseLocale(String parseLocale_) {
+        this.parseLocale_ = parseLocale_;
+    }
+
+
+    //*********************************************************************
+    // Private (utility) methods
+
+    // (re)initializes state (during release() or construction)
+    private void init() {
+        // null implies "no expression"
+	value_ = type_ = dateStyle_ = timeStyle_ = pattern_ = timeZone_ = null;
+	parseLocale_ = null;
+    }
+
+    // Evaluates expressions as necessary
+    private void evaluateExpressions() throws JspException {
+        /* 
+         * Note: we don't check for type mismatches here; we assume
+         * the expression evaluator will return the expected type
+         * (by virtue of knowledge we give it about what that type is).
+         * A ClassCastException here is truly unexpected, so we let it
+         * propagate up.
+         */
+
+	// 'value' attribute
+	if (value_ != null) {
+	    value = (String) ExpressionEvaluatorManager.evaluate(
+	        "value", value_, String.class, this, pageContext);
+	}
+
+	// 'type' attribute
+	if (type_ != null) {
+	    type = (String) ExpressionEvaluatorManager.evaluate(
+	        "type", type_, String.class, this, pageContext);
+	}
+
+	// 'dateStyle' attribute
+	if (dateStyle_ != null) {
+	    dateStyle = (String) ExpressionEvaluatorManager.evaluate(
+	        "dateStyle", dateStyle_, String.class, this, pageContext);
+	}
+
+	// 'timeStyle' attribute
+	if (timeStyle_ != null) {
+	    timeStyle = (String) ExpressionEvaluatorManager.evaluate(
+	        "timeStyle", timeStyle_, String.class, this, pageContext);
+	}
+
+	// 'pattern' attribute
+	if (pattern_ != null) {
+	    pattern = (String) ExpressionEvaluatorManager.evaluate(
+	        "pattern", pattern_, String.class, this, pageContext);
+	}
+
+	// 'timeZone' attribute
+	if (timeZone_ != null) {
+	    timeZone = ExpressionEvaluatorManager.evaluate(
+	        "timeZone", timeZone_, Object.class, this, pageContext);
+	}
+
+	// 'parseLocale' attribute
+	if (parseLocale_ != null) {
+	    Object obj = ExpressionEvaluatorManager.evaluate(
+	        "parseLocale", parseLocale_, Object.class, this, pageContext);
+	    if (obj != null) {
+		if (obj instanceof Locale) {
+		    parseLocale = (Locale) obj;
+		} else {
+		    String localeStr = (String) obj;
+		    if (!"".equals(localeStr)) {
+			parseLocale = SetLocaleSupport.parseLocale(localeStr);
+		    }
+		}
+	    }
+	}
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/el/fmt/ParseNumberTag.java b/standard/src/org/apache/taglibs/standard/tag/el/fmt/ParseNumberTag.java
new file mode 100644
index 0000000..94199cf
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/el/fmt/ParseNumberTag.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.el.fmt;
+
+import java.util.Locale;
+
+import javax.servlet.jsp.JspException;
+
+import org.apache.taglibs.standard.lang.support.ExpressionEvaluatorManager;
+import org.apache.taglibs.standard.tag.common.fmt.ParseNumberSupport;
+import org.apache.taglibs.standard.tag.common.fmt.SetLocaleSupport;
+
+/**
+ * <p>A handler for <parseNumber> that accepts attributes as Strings
+ * and evaluates them as expressions at runtime.</p>
+ *
+ * @author Jan Luehe
+ */
+
+public class ParseNumberTag extends ParseNumberSupport {
+
+    //*********************************************************************
+    // 'Private' state (implementation details)
+
+    private String value_;                       // stores EL-based property
+    private String type_;                        // stores EL-based property
+    private String pattern_;		         // stores EL-based property
+    private String parseLocale_;	         // stores EL-based property
+    private String integerOnly_;	         // stores EL-based property
+
+
+    //*********************************************************************
+    // Constructor
+
+    /**
+     * Constructs a new ParseNumberTag.  As with TagSupport, subclasses
+     * should not provide other constructors and are expected to call
+     * the superclass constructor
+     */
+    public ParseNumberTag() {
+        super();
+        init();
+    }
+
+
+    //*********************************************************************
+    // Tag logic
+
+    // evaluates expression and chains to parent
+    public int doStartTag() throws JspException {
+
+        // evaluate any expressions we were passed, once per invocation
+        evaluateExpressions();
+
+	// chain to the parent implementation
+	return super.doStartTag();
+    }
+
+    // Releases any resources we may have (or inherit)
+    public void release() {
+        super.release();
+        init();
+    }
+
+
+    //*********************************************************************
+    // Accessor methods
+
+    // for EL-based attribute
+    public void setValue(String value_) {
+        this.value_ = value_;
+	this.valueSpecified = true;
+    }
+
+    // for EL-based attribute
+    public void setType(String type_) {
+        this.type_ = type_;
+    }
+
+    // for EL-based attribute
+    public void setPattern(String pattern_) {
+        this.pattern_ = pattern_;
+    }
+
+    // for EL-based attribute
+    public void setParseLocale(String parseLocale_) {
+        this.parseLocale_ = parseLocale_;
+    }
+
+    // for EL-based attribute
+    public void setIntegerOnly(String integerOnly_) {
+        this.integerOnly_ = integerOnly_;
+	this.integerOnlySpecified = true;
+    }
+
+
+    //*********************************************************************
+    // Private (utility) methods
+
+    // (re)initializes state (during release() or construction)
+    private void init() {
+        // null implies "no expression"
+	value_ = type_ = pattern_ = parseLocale_ = integerOnly_ = null;
+    }
+
+    // Evaluates expressions as necessary
+    private void evaluateExpressions() throws JspException {
+	Object obj = null;
+
+        /* 
+         * Note: we don't check for type mismatches here; we assume
+         * the expression evaluator will return the expected type
+         * (by virtue of knowledge we give it about what that type is).
+         * A ClassCastException here is truly unexpected, so we let it
+         * propagate up.
+         */
+
+	// 'value' attribute
+	if (value_ != null) {
+	    value = (String) ExpressionEvaluatorManager.evaluate(
+	        "value", value_, String.class, this, pageContext);
+	}
+
+	// 'type' attribute
+	if (type_ != null) {
+	    type = (String) ExpressionEvaluatorManager.evaluate(
+	        "type", type_, String.class, this, pageContext);
+	}
+
+	// 'pattern' attribute
+	if (pattern_ != null) {
+	    pattern = (String) ExpressionEvaluatorManager.evaluate(
+	        "pattern", pattern_, String.class, this, pageContext);
+	}
+
+	// 'parseLocale' attribute
+	if (parseLocale_ != null) {
+	    obj = ExpressionEvaluatorManager.evaluate(
+	        "parseLocale", parseLocale_, Object.class, this, pageContext);
+	    if (obj != null) {
+		if (obj instanceof Locale) {
+		    parseLocale = (Locale) obj;
+		} else {
+		    String localeStr = (String) obj;
+		    if (!"".equals(localeStr)) {
+			parseLocale = SetLocaleSupport.parseLocale(localeStr);
+		    }
+		}
+	    }
+	}
+
+	// 'integerOnly' attribute
+	if (integerOnly_ != null) {
+	    obj = ExpressionEvaluatorManager.evaluate(
+	        "integerOnly", integerOnly_, Boolean.class, this, pageContext);
+	    if (obj != null) {
+		isIntegerOnly = ((Boolean) obj).booleanValue();
+	    }
+	}
+    }
+}
+
diff --git a/standard/src/org/apache/taglibs/standard/tag/el/fmt/RequestEncodingTag.java b/standard/src/org/apache/taglibs/standard/tag/el/fmt/RequestEncodingTag.java
new file mode 100644
index 0000000..8c69dfa
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/el/fmt/RequestEncodingTag.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.el.fmt;
+
+import javax.servlet.jsp.JspException;
+
+import org.apache.taglibs.standard.lang.support.ExpressionEvaluatorManager;
+import org.apache.taglibs.standard.tag.common.fmt.RequestEncodingSupport;
+
+/**
+ * <p>A handler for <requestEncoding> that accepts attributes as Strings
+ * and evaluates them as expressions at runtime.</p>
+ *
+ * @author Jan Luehe
+ */
+
+public class RequestEncodingTag extends RequestEncodingSupport {
+
+    //*********************************************************************
+    // 'Private' state (implementation details)
+
+    private String value_;                    // stores EL-based property
+
+
+    //*********************************************************************
+    // Constructor
+
+    /**
+     * Constructs a new RequestEncodingTag.  As with TagSupport, subclasses
+     * should not provide other constructors and are expected to call
+     * the superclass constructor
+     */
+    public RequestEncodingTag() {
+        super();
+        init();
+    }
+
+
+    //*********************************************************************
+    // Tag logic
+
+    // evaluates expression and chains to parent
+    public int doStartTag() throws JspException {
+
+        // evaluate any expressions we were passed, once per invocation
+        evaluateExpressions();
+
+	// chain to the parent implementation
+	return super.doStartTag();
+    }
+
+    // Releases any resources we may have (or inherit)
+    public void release() {
+        super.release();
+        init();
+    }
+
+
+    //*********************************************************************
+    // Accessor methods
+
+    // for EL-based attribute
+    public void setValue(String value_) {
+        this.value_ = value_;
+    }
+
+
+    //*********************************************************************
+    // Private (utility) methods
+
+    // (re)initializes state (during release() or construction)
+    private void init() {
+        // null implies "no expression"
+	value_ = null;
+    }
+
+    // Evaluates expressions as necessary
+    private void evaluateExpressions() throws JspException {
+        /* 
+         * Note: we don't check for type mismatches here; we assume
+         * the expression evaluator will return the expected type
+         * (by virtue of knowledge we give it about what that type is).
+         * A ClassCastException here is truly unexpected, so we let it
+         * propagate up.
+         */
+
+	if (value_ != null) {
+	    value = (String) ExpressionEvaluatorManager.evaluate(
+	        "value", value_, String.class, this, pageContext);
+	}
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/el/fmt/SetBundleTag.java b/standard/src/org/apache/taglibs/standard/tag/el/fmt/SetBundleTag.java
new file mode 100644
index 0000000..fd1e1a3
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/el/fmt/SetBundleTag.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.el.fmt;
+
+import javax.servlet.jsp.JspException;
+
+import org.apache.taglibs.standard.lang.support.ExpressionEvaluatorManager;
+import org.apache.taglibs.standard.tag.common.fmt.SetBundleSupport;
+
+/**
+ * <p>A handler for <setBundle> that accepts attributes as Strings
+ * and evaluates them as expressions at runtime.</p>
+ *
+ * @author Shawn Bayern
+ * @author Jan Luehe
+ */
+
+public class SetBundleTag extends SetBundleSupport {
+
+    //*********************************************************************
+    // 'Private' state (implementation details)
+
+    private String basename_;                    // stores EL-based property
+
+
+    //*********************************************************************
+    // Constructor
+
+    /**
+     * Constructs a new SetBundleTag.  As with TagSupport, subclasses
+     * should not provide other constructors and are expected to call
+     * the superclass constructor
+     */
+    public SetBundleTag() {
+        super();
+        init();
+    }
+
+
+    //*********************************************************************
+    // Tag logic
+
+    // evaluates expression and chains to parent
+    public int doStartTag() throws JspException {
+
+        // evaluate any expressions we were passed, once per invocation
+        evaluateExpressions();
+
+	// chain to the parent implementation
+	return super.doStartTag();
+    }
+
+    // Releases any resources we may have (or inherit)
+    public void release() {
+        super.release();
+        init();
+    }
+
+
+    //*********************************************************************
+    // Accessor methods
+
+    // for EL-based attribute
+    public void setBasename(String basename_) {
+        this.basename_ = basename_;
+    }
+
+
+    //*********************************************************************
+    // Private (utility) methods
+
+    // (re)initializes state (during release() or construction)
+    private void init() {
+        // null implies "no expression"
+	basename_ = null;
+    }
+
+    // Evaluates expressions as necessary
+    private void evaluateExpressions() throws JspException {
+
+	// 'basename' attribute (mandatory)
+	basename = (String) ExpressionEvaluatorManager.evaluate(
+	    "basename", basename_, String.class, this, pageContext);
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/el/fmt/SetLocaleTag.java b/standard/src/org/apache/taglibs/standard/tag/el/fmt/SetLocaleTag.java
new file mode 100644
index 0000000..4941f67
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/el/fmt/SetLocaleTag.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.el.fmt;
+
+import javax.servlet.jsp.JspException;
+
+import org.apache.taglibs.standard.lang.support.ExpressionEvaluatorManager;
+import org.apache.taglibs.standard.tag.common.fmt.SetLocaleSupport;
+
+/**
+ * <p>A handler for <setLocale> that accepts attributes as Strings
+ * and evaluates them as expressions at runtime.</p>
+ *
+ * @author Jan Luehe
+ */
+
+public class SetLocaleTag extends SetLocaleSupport {
+
+    //*********************************************************************
+    // 'Private' state (implementation details)
+
+    private String value_;                      // stores EL-based property
+    private String variant_;                    // stores EL-based property
+
+
+    //*********************************************************************
+    // Constructor
+
+    /**
+     * Constructs a new LocaleTag.  As with TagSupport, subclasses
+     * should not provide other constructors and are expected to call
+     * the superclass constructor
+     */
+    public SetLocaleTag() {
+        super();
+        init();
+    }
+
+
+    //*********************************************************************
+    // Tag logic
+
+    // evaluates expression and chains to parent
+    public int doStartTag() throws JspException {
+
+        // evaluate any expressions we were passed, once per invocation
+        evaluateExpressions();
+
+	// chain to the parent implementation
+	return super.doStartTag();
+    }
+
+    // Releases any resources we may have (or inherit)
+    public void release() {
+        super.release();
+        init();
+    }
+
+
+    //*********************************************************************
+    // Accessor methods
+
+    // for EL-based attribute
+    public void setValue(String value_) {
+        this.value_ = value_;
+    }
+
+    // for EL-based attribute
+    public void setVariant(String variant_) {
+        this.variant_ = variant_;
+    }
+
+
+    //*********************************************************************
+    // Private (utility) methods
+
+    // (re)initializes state (during release() or construction)
+    private void init() {
+        // null implies "no expression"
+	value_ = variant_ = null;
+    }
+
+    // Evaluates expressions as necessary
+    private void evaluateExpressions() throws JspException {
+
+	// 'value' attribute (mandatory)
+	value = ExpressionEvaluatorManager.evaluate(
+	    "value", value_, Object.class, this, pageContext);
+
+	// 'variant' attribute (optional)
+	if (variant_ != null) {
+	    variant = (String) ExpressionEvaluatorManager.evaluate(
+	        "variant", variant_, String.class, this, pageContext);
+	}
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/el/fmt/SetTimeZoneTag.java b/standard/src/org/apache/taglibs/standard/tag/el/fmt/SetTimeZoneTag.java
new file mode 100644
index 0000000..70c9379
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/el/fmt/SetTimeZoneTag.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.el.fmt;
+
+import javax.servlet.jsp.JspException;
+
+import org.apache.taglibs.standard.lang.support.ExpressionEvaluatorManager;
+import org.apache.taglibs.standard.tag.common.fmt.SetTimeZoneSupport;
+
+/**
+ * <p>A handler for <setTimeZone> that accepts attributes as Strings
+ * and evaluates them as expressions at runtime.</p>
+ *
+ * @author Shawn Bayern
+ * @author Jan Luehe
+ */
+
+public class SetTimeZoneTag extends SetTimeZoneSupport {
+
+    //*********************************************************************
+    // 'Private' state (implementation details)
+
+    private String value_;                    // stores EL-based property
+
+
+    //*********************************************************************
+    // Constructor
+
+    /**
+     * Constructs a new TimeZoneTag.  As with TagSupport, subclasses
+     * should not provide other constructors and are expected to call
+     * the superclass constructor
+     */
+    public SetTimeZoneTag() {
+        super();
+        init();
+    }
+
+
+    //*********************************************************************
+    // Tag logic
+
+    // evaluates expression and chains to parent
+    public int doStartTag() throws JspException {
+
+        // evaluate any expressions we were passed, once per invocation
+        evaluateExpressions();
+
+	// chain to the parent implementation
+	return super.doStartTag();
+    }
+
+    // Releases any resources we may have (or inherit)
+    public void release() {
+        super.release();
+        init();
+    }
+
+
+    //*********************************************************************
+    // Accessor methods
+
+    // for EL-based attribute
+    public void setValue(String value_) {
+        this.value_ = value_;
+    }
+
+
+    //*********************************************************************
+    // Private (utility) methods
+
+    // (re)initializes state (during release() or construction)
+    private void init() {
+        // null implies "no expression"
+	value_ = null;
+    }
+
+    // Evaluates expressions as necessary
+    private void evaluateExpressions() throws JspException {
+	
+	// 'value' attribute (mandatory)
+	value = ExpressionEvaluatorManager.evaluate(
+	    "value", value_, Object.class, this, pageContext);
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/el/fmt/TimeZoneTag.java b/standard/src/org/apache/taglibs/standard/tag/el/fmt/TimeZoneTag.java
new file mode 100644
index 0000000..5b111d5
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/el/fmt/TimeZoneTag.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.el.fmt;
+
+import javax.servlet.jsp.JspException;
+
+import org.apache.taglibs.standard.lang.support.ExpressionEvaluatorManager;
+import org.apache.taglibs.standard.tag.common.fmt.TimeZoneSupport;
+
+/**
+ * <p>A handler for <timeZone> that accepts attributes as Strings
+ * and evaluates them as expressions at runtime.</p>
+ *
+ * @author Shawn Bayern
+ * @author Jan Luehe
+ */
+
+public class TimeZoneTag extends TimeZoneSupport {
+
+    //*********************************************************************
+    // 'Private' state (implementation details)
+
+    private String value_;                    // stores EL-based property
+
+
+    //*********************************************************************
+    // Constructor
+
+    /**
+     * Constructs a new TimeZoneTag.  As with TagSupport, subclasses
+     * should not provide other constructors and are expected to call
+     * the superclass constructor
+     */
+    public TimeZoneTag() {
+        super();
+        init();
+    }
+
+
+    //*********************************************************************
+    // Tag logic
+
+    // evaluates expression and chains to parent
+    public int doStartTag() throws JspException {
+
+        // evaluate any expressions we were passed, once per invocation
+        evaluateExpressions();
+
+	// chain to the parent implementation
+	return super.doStartTag();
+    }
+
+    // Releases any resources we may have (or inherit)
+    public void release() {
+        super.release();
+        init();
+    }
+
+
+    //*********************************************************************
+    // Accessor methods
+
+    // for EL-based attribute
+    public void setValue(String value_) {
+        this.value_ = value_;
+    }
+
+
+    //*********************************************************************
+    // Private (utility) methods
+
+    // (re)initializes state (during release() or construction)
+    private void init() {
+        // null implies "no expression"
+	value_ = null;
+    }
+
+    // Evaluates expressions as necessary
+    private void evaluateExpressions() throws JspException {
+
+	// 'value' attribute (mandatory)
+	value = ExpressionEvaluatorManager.evaluate(
+	    "value", value_, Object.class, this, pageContext);
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/el/sql/DateParamTag.java b/standard/src/org/apache/taglibs/standard/tag/el/sql/DateParamTag.java
new file mode 100644
index 0000000..4ceab81
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/el/sql/DateParamTag.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.el.sql;
+
+import java.util.Date;
+
+import javax.servlet.jsp.JspException;
+
+import org.apache.taglibs.standard.lang.support.ExpressionEvaluatorManager;
+import org.apache.taglibs.standard.tag.common.sql.DateParamTagSupport;
+
+/**
+ * Subclass for the JSTL library with EL support.
+ *
+ * @author Justyna Horwat
+ */
+public class DateParamTag extends DateParamTagSupport {
+    
+    private String valueEL;
+    private String typeEL;
+
+    public void setValue(String valueEL) {
+	this.valueEL = valueEL;
+    }
+
+    public void setType(String typeEL) {
+	this.typeEL = typeEL;
+    }
+
+    public int doStartTag() throws JspException {
+        evaluateExpressions();
+	return super.doStartTag();
+    }
+
+    //*********************************************************************
+    // Private utility methods
+
+    // Evaluates expressions as necessary
+    private void evaluateExpressions() throws JspException {
+	if (valueEL != null) {
+	    value = (Date) ExpressionEvaluatorManager.evaluate(
+                "value", valueEL, Date.class, this, pageContext);
+	}
+
+	if (typeEL != null) {
+	    type = (String) ExpressionEvaluatorManager.evaluate(
+                "type", typeEL, String.class, this, pageContext);
+        }
+    }
+
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/el/sql/ParamTag.java b/standard/src/org/apache/taglibs/standard/tag/el/sql/ParamTag.java
new file mode 100644
index 0000000..6e50766
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/el/sql/ParamTag.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.el.sql;
+
+import javax.servlet.jsp.JspException;
+
+import org.apache.taglibs.standard.lang.support.ExpressionEvaluatorManager;
+import org.apache.taglibs.standard.tag.common.sql.ParamTagSupport;
+
+/**
+ * Subclass for the JSTL library with EL support.
+ *
+ * @author Hans Bergsten
+ */
+public class ParamTag extends ParamTagSupport {
+    
+    private String valueEL;
+
+    public void setValue(String valueEL) {
+	this.valueEL = valueEL;
+    }
+
+    public int doStartTag() throws JspException {
+	if (valueEL != null) {
+	    value = (Object) 
+		ExpressionEvaluatorManager.evaluate("value", valueEL, 
+		    Object.class, this, pageContext);
+	}
+	return super.doStartTag();
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/el/sql/QueryTag.java b/standard/src/org/apache/taglibs/standard/tag/el/sql/QueryTag.java
new file mode 100644
index 0000000..3434b3d
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/el/sql/QueryTag.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.el.sql;
+
+import javax.servlet.jsp.JspException;
+
+import org.apache.taglibs.standard.lang.support.ExpressionEvaluatorManager;
+import org.apache.taglibs.standard.tag.common.sql.QueryTagSupport;
+
+/**
+ * Subclass for the JSTL library with EL support.
+ *
+ * @author Hans Bergsten
+ * @author Justyna Horwat
+ */
+public class QueryTag extends QueryTagSupport {
+
+    private String dataSourceEL;
+    private String sqlEL;
+    private String startRowEL;
+    private String maxRowsEL;
+
+    //*********************************************************************
+    // Constructor
+
+    /**
+     * Constructs a new QueryTag.  As with TagSupport, subclasses
+     * should not provide other constructors and are expected to call
+     * the superclass constructor
+     */
+    public QueryTag() {
+        super();
+    }
+
+    //*********************************************************************
+    // Accessor methods
+
+    public void setDataSource(String dataSourceEL) {
+	this.dataSourceEL = dataSourceEL;
+	this.dataSourceSpecified = true;
+    }
+
+    /**
+     * The index of the first row returned can be
+     * specified using startRow.
+     */
+    public void setStartRow(String startRowEL) {
+	this.startRowEL = startRowEL;
+    }
+
+    /**
+     * Query result can be limited by specifying
+     * the maximum number of rows returned.
+     */
+    public void setMaxRows(String maxRowsEL) {
+	this.maxRowsEL = maxRowsEL;
+	this.maxRowsSpecified = true;
+    }
+
+    /**
+     * Setter method for the SQL statement to use for the
+     * query. The statement may contain parameter markers
+     * (question marks, ?). If so, the parameter values must
+     * be set using nested value elements.
+     */
+    public void setSql(String sqlEL) {
+	this.sqlEL = sqlEL;
+    }
+
+    public int doStartTag() throws JspException {
+        evaluateExpressions();
+	return super.doStartTag();
+    }
+
+    //*********************************************************************
+    // Private utility methods
+
+    // Evaluates expressions as necessary
+    private void evaluateExpressions() throws JspException {
+        Integer tempInt = null;
+
+        if (dataSourceEL != null) {
+            rawDataSource = (Object) ExpressionEvaluatorManager.evaluate(
+                "dataSource", dataSourceEL, Object.class, this, pageContext);
+        }
+
+        if (sqlEL != null) {
+            sql = (String) ExpressionEvaluatorManager.evaluate("sql", sqlEL,
+                String.class, this, pageContext);
+        }
+
+	if (startRowEL != null) {
+	    tempInt = (Integer) ExpressionEvaluatorManager.evaluate(
+                "startRow", startRowEL, Integer.class, this, pageContext);
+	    if (tempInt != null)
+		startRow = tempInt.intValue();
+	}
+
+	if (maxRowsEL != null) {
+	    tempInt = (Integer) ExpressionEvaluatorManager.evaluate(
+                "maxRows", maxRowsEL, Integer.class, this, pageContext);
+	    if (tempInt != null)
+		maxRows = tempInt.intValue();
+	}
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/el/sql/SetDataSourceTag.java b/standard/src/org/apache/taglibs/standard/tag/el/sql/SetDataSourceTag.java
new file mode 100644
index 0000000..6ca0f74
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/el/sql/SetDataSourceTag.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.el.sql;
+
+import javax.servlet.jsp.JspException;
+
+import org.apache.taglibs.standard.lang.support.ExpressionEvaluatorManager;
+import org.apache.taglibs.standard.tag.common.sql.SetDataSourceTagSupport;
+
+/**
+ * <p>Tag handler for <SetDataSource> in JSTL, used to create
+ * a simple DataSource for prototyping.</p>
+ * 
+ */
+public class SetDataSourceTag extends SetDataSourceTagSupport {
+
+    private String dataSourceEL;
+    private String driverClassNameEL;
+    private String jdbcURLEL;
+    private String userNameEL;
+    private String passwordEL;
+
+    //*********************************************************************
+    // Accessor methods
+
+    public void setDataSource(String dataSourceEL) {
+	this.dataSourceEL = dataSourceEL;
+	this.dataSourceSpecified = true;
+    }
+
+    public void setDriver(String driverClassNameEL) {
+	this.driverClassNameEL = driverClassNameEL;
+    }
+
+    public void setUrl(String jdbcURLEL) {
+	this.jdbcURLEL = jdbcURLEL;
+    }
+
+    public void setUser(String userNameEL) {
+	this.userNameEL = userNameEL;
+    }
+
+    public void setPassword(String passwordEL) {
+	this.passwordEL = passwordEL;
+    }
+
+    //*********************************************************************
+    // Tag logic
+
+    public int doStartTag() throws JspException {
+        evaluateExpressions();
+
+        return super.doStartTag();
+    }
+
+
+    //*********************************************************************
+    // Private utility methods
+
+    // Evaluates expressions as necessary
+    private void evaluateExpressions() throws JspException {
+        if (dataSourceEL != null) {
+                dataSource = ExpressionEvaluatorManager.evaluate
+                ("dataSource", dataSourceEL, Object.class, this, pageContext);
+        }
+
+        if (driverClassNameEL != null) {
+                driverClassName = (String) ExpressionEvaluatorManager.evaluate
+                ("driver", driverClassNameEL, String.class, this, pageContext);
+        }
+
+        if (jdbcURLEL != null) {
+                jdbcURL = (String) ExpressionEvaluatorManager.evaluate
+                ("url", jdbcURLEL, String.class, this, pageContext);
+        }
+
+        if (userNameEL != null) {
+                userName = (String) ExpressionEvaluatorManager.evaluate
+                ("user", userNameEL, String.class, this, pageContext);
+        }
+
+        if (passwordEL != null) {
+                password = (String) ExpressionEvaluatorManager.evaluate
+                ("password", passwordEL, String.class, this, pageContext);
+        }
+    }
+
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/el/sql/TransactionTag.java b/standard/src/org/apache/taglibs/standard/tag/el/sql/TransactionTag.java
new file mode 100644
index 0000000..7de2e91
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/el/sql/TransactionTag.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.el.sql;
+
+import javax.servlet.jsp.JspException;
+
+import org.apache.taglibs.standard.lang.support.ExpressionEvaluatorManager;
+import org.apache.taglibs.standard.tag.common.sql.TransactionTagSupport;
+
+/**
+ * Subclass for the JSTL library with EL support.
+ *
+ * @author Hans Bergsten
+ * @author Justyna Horwat
+ */
+public class TransactionTag extends TransactionTagSupport {
+    
+    private String dataSourceEL;
+    private String isolationEL;
+
+    public void setDataSource(String dataSourceEL) {
+	this.dataSourceEL = dataSourceEL;
+	this.dataSourceSpecified = true;
+    }
+
+    public void setIsolation(String isolationEL) {
+	this.isolationEL = isolationEL;
+    }
+
+    public int doStartTag() throws JspException {
+	if (dataSourceEL != null) {
+	    rawDataSource = (Object) 
+		ExpressionEvaluatorManager.evaluate("dataSource", 
+		    dataSourceEL, Object.class, this, pageContext);
+	}
+
+	if (isolationEL != null) {
+	    isolationEL = (String) 
+		ExpressionEvaluatorManager.evaluate("isolation", 
+		    isolationEL, String.class, this, pageContext);
+            super.setIsolation(isolationEL);
+	}
+
+	return super.doStartTag();
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/el/sql/UpdateTag.java b/standard/src/org/apache/taglibs/standard/tag/el/sql/UpdateTag.java
new file mode 100644
index 0000000..9aa231a
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/el/sql/UpdateTag.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.el.sql;
+
+import javax.servlet.jsp.JspException;
+
+import org.apache.taglibs.standard.lang.support.ExpressionEvaluatorManager;
+import org.apache.taglibs.standard.tag.common.sql.UpdateTagSupport;
+
+/**
+ * Subclass for the JSTL library with EL support.
+ *
+ * @author Hans Bergsten
+ */
+public class UpdateTag extends UpdateTagSupport {
+    
+    private String dataSourceEL;
+    private String sqlEL;
+
+    public void setDataSource(String dataSourceEL) {
+	this.dataSourceEL = dataSourceEL;
+	this.dataSourceSpecified = true;
+    }
+
+    /**
+     * Setter method for the SQL statement to use for the
+     * query. The statement may contain parameter markers
+     * (question marks, ?). If so, the parameter values must
+     * be set using nested value elements.
+     */
+    public void setSql(String sqlEL) {
+	this.sqlEL = sqlEL;
+    }
+
+    public int doStartTag() throws JspException {
+	if (dataSourceEL != null) {
+	    rawDataSource = (Object) 
+		ExpressionEvaluatorManager.evaluate("dataSource", 
+		    dataSourceEL, Object.class, this, pageContext);
+	}
+	if (sqlEL != null) {
+	    sql = (String) ExpressionEvaluatorManager.evaluate("sql", sqlEL, 
+	        String.class, this, pageContext);
+	}
+	return super.doStartTag();
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/el/xml/ExprTag.java b/standard/src/org/apache/taglibs/standard/tag/el/xml/ExprTag.java
new file mode 100644
index 0000000..4e7e3ac
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/el/xml/ExprTag.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.el.xml;
+
+import javax.servlet.jsp.JspException;
+
+import org.apache.taglibs.standard.tag.common.xml.ExprSupport;
+import org.apache.taglibs.standard.tag.el.core.ExpressionUtil;
+
+/**
+ * <p>A handler for <out> that accepts attributes as Strings
+ * and evaluates them as expressions at runtime.</p>
+ *
+ * @author Shawn Bayern
+ */
+public class ExprTag extends ExprSupport {
+
+    //*********************************************************************
+    // 'Private' state (implementation details)
+
+    private String escapeXml_;                  // stores EL-based property
+
+
+    //*********************************************************************
+    // Constructor
+
+    /**
+     * Constructs a new handler.  As with TagSupport, subclasses
+     * should not provide other constructors and are expected to call
+     * the superclass constructor
+     */
+    public ExprTag() {
+        super();
+        init();
+    }
+
+
+    //*********************************************************************
+    // Tag logic
+
+    // evaluates expression and chains to parent
+    public int doStartTag() throws JspException {
+
+        // evaluate any expressions we were passed, once per invocation
+        evaluateExpressions();
+
+	// chain to the parent implementation
+	return super.doStartTag();
+    }
+
+
+    // Releases any resources we may have (or inherit)
+    public void release() {
+        super.release();
+        init();
+    }
+
+
+    //*********************************************************************
+    // Accessor methods
+
+    // for EL-based attribute
+    public void setEscapeXml(String escapeXml_) {
+        this.escapeXml_ = escapeXml_;
+    }
+
+
+    //*********************************************************************
+    // Private (utility) methods
+
+    // (re)initializes state (during release() or construction)
+    private void init() {
+        // null implies "no expression"
+	escapeXml_ = null;
+    }
+
+    /* Evaluates expressions as necessary */
+    private void evaluateExpressions() throws JspException {
+        /* 
+         * Note: we don't check for type mismatches here; we assume
+         * the expression evaluator will return the expected type
+         * (by virtue of knowledge we give it about what that type is).
+         * A ClassCastException here is truly unexpected, so we let it
+         * propagate up.
+         */
+
+        if (escapeXml_ != null) {
+            Boolean b = (Boolean) ExpressionUtil.evalNotNull(
+                "out",
+                "escapeXml",
+                escapeXml_,
+                Boolean.class,
+                this,
+                pageContext);
+            if (b == null)
+                escapeXml = false;
+            else
+                escapeXml = b.booleanValue();
+        }
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/el/xml/ParamTag.java b/standard/src/org/apache/taglibs/standard/tag/el/xml/ParamTag.java
new file mode 100644
index 0000000..68c113b
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/el/xml/ParamTag.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.el.xml;
+
+import javax.servlet.jsp.JspException;
+
+import org.apache.taglibs.standard.tag.common.xml.ParamSupport;
+import org.apache.taglibs.standard.tag.el.core.ExpressionUtil;
+
+/**
+ * <p>A handler for <param> that accepts attributes as Strings
+ * and evaluates them as expressions at runtime.</p>
+ *
+ * @author Shawn Bayern
+ */
+
+public class ParamTag extends ParamSupport {
+
+    //*********************************************************************
+    // 'Private' state (implementation details)
+
+    private String name_;                       // stores EL-based property
+    private String value_;			// stores EL-based property
+
+
+    //*********************************************************************
+    // Constructor
+
+    public ParamTag() {
+        super();
+        init();
+    }
+
+
+    //*********************************************************************
+    // Tag logic
+
+    // evaluates expression and chains to parent
+    public int doStartTag() throws JspException {
+
+        // evaluate any expressions we were passed, once per invocation
+        evaluateExpressions();
+
+	// chain to the parent implementation
+	return super.doStartTag();
+    }
+
+
+    // Releases any resources we may have (or inherit)
+    public void release() {
+        super.release();
+        init();
+    }
+
+
+    //*********************************************************************
+    // Accessor methods
+
+    // for EL-based attribute
+    public void setName(String name_) {
+        this.name_ = name_;
+    }
+
+    public void setValue(String value_) {
+        this.value_ = value_;
+    }
+
+
+    //*********************************************************************
+    // Private (utility) methods
+
+    // (re)initializes state (during release() or construction)
+    private void init() {
+        // null implies "no expression"
+	name_ = value_ = null;
+    }
+
+    /* Evaluates expressions as necessary */
+    private void evaluateExpressions() throws JspException {
+        /* 
+         * Note: we don't check for type mismatches here; we assume
+         * the expression evaluator will return the expected type
+         * (by virtue of knowledge we give it about what that type is).
+         * A ClassCastException here is truly unexpected, so we let it
+         * propagate up.
+         */
+
+	name = (String) ExpressionUtil.evalNotNull(
+	    "param", "name", name_, String.class, this, pageContext);
+	value = ExpressionUtil.evalNotNull(
+	    "param", "value", value_, Object.class, this, pageContext);
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/el/xml/ParseTag.java b/standard/src/org/apache/taglibs/standard/tag/el/xml/ParseTag.java
new file mode 100644
index 0000000..9810f68
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/el/xml/ParseTag.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.el.xml;
+
+import javax.servlet.jsp.JspException;
+
+import org.apache.taglibs.standard.tag.common.core.NullAttributeException;
+import org.apache.taglibs.standard.tag.common.xml.ParseSupport;
+import org.apache.taglibs.standard.tag.el.core.ExpressionUtil;
+import org.xml.sax.XMLFilter;
+
+/**
+ * <p>A handler for <parse> that accepts attributes as Strings
+ * and evaluates them as expressions at runtime.</p>
+ *
+ * @author Shawn Bayern
+ */
+public class ParseTag extends ParseSupport {
+
+    //*********************************************************************
+    // 'Private' state (implementation details)
+
+    private String xml_;                    // stores EL-based property
+    private String systemId_;		    // stores EL-based property
+    private String filter_;		    // stores EL-based property
+
+
+    //*********************************************************************
+    // Constructor
+
+    /**
+     * Constructs a new ParseTag.  As with TagSupport, subclasses
+     * should not provide other constructors and are expected to call
+     * the superclass constructor
+     */
+    public ParseTag() {
+        super();
+        init();
+    }
+
+
+    //*********************************************************************
+    // Tag logic
+
+    // evaluates expression and chains to parent
+    public int doStartTag() throws JspException {
+
+        // evaluate any expressions we were passed, once per invocation
+        evaluateExpressions();
+
+	// chain to the parent implementation
+	return super.doStartTag();
+    }
+
+
+    // Releases any resources we may have (or inherit)
+    public void release() {
+        super.release();
+        init();
+    }
+
+
+    //*********************************************************************
+    // Accessor methods
+
+    // for EL-based attribute
+    public void setFilter(String filter_) {
+        this.filter_ = filter_;
+    }
+
+    public void setXml(String xml_) {
+        this.xml_ = xml_;
+    }
+
+    public void setSystemId(String systemId_) {
+        this.systemId_ = systemId_;
+    }
+
+
+    //*********************************************************************
+    // Private (utility) methods
+
+    // (re)initializes state (during release() or construction)
+    private void init() {
+        // null implies "no expression"
+	filter_ = xml_ = systemId_ = null;
+    }
+
+    /* Evaluates expressions as necessary */
+    private void evaluateExpressions() throws JspException {
+        /* 
+         * Note: we don't check for type mismatches here; we assume
+         * the expression evaluator will return the expected type
+         * (by virtue of knowledge we give it about what that type is).
+         * A ClassCastException here is truly unexpected, so we let it
+         * propagate up.
+         */
+
+	xml = ExpressionUtil.evalNotNull(
+	    "parse", "xml", xml_, Object.class, this, pageContext);
+	systemId = (String) ExpressionUtil.evalNotNull(
+	    "parse", "systemId", systemId_, String.class, this, pageContext);
+
+	try {
+	    filter = (XMLFilter) ExpressionUtil.evalNotNull(
+	        "parse", "filter", filter_, XMLFilter.class, this, pageContext);
+	} catch (NullAttributeException ex) {
+	    // explicitly let 'filter' be null
+	    filter = null;
+	}
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/el/xml/TransformTag.java b/standard/src/org/apache/taglibs/standard/tag/el/xml/TransformTag.java
new file mode 100644
index 0000000..1f6d00f
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/el/xml/TransformTag.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.el.xml;
+
+import javax.servlet.jsp.JspException;
+import javax.xml.transform.Result;
+
+import org.apache.taglibs.standard.tag.common.xml.TransformSupport;
+import org.apache.taglibs.standard.tag.el.core.ExpressionUtil;
+
+/**
+ * <p>A handler for <transform> that accepts attributes as Strings
+ * and evaluates them as expressions at runtime.</p>
+ *
+ * @author Shawn Bayern
+ */
+public class TransformTag extends TransformSupport {
+
+    //*********************************************************************
+    // 'Private' state (implementation details)
+
+    private String xml_;                        // stores EL-based property
+    private String xmlSystemId_;                // stores EL-based property
+    private String xslt_;			// stores EL-based property
+    private String xsltSystemId_;		// stores EL-based property
+    private String result_;			// stores EL-based property
+
+
+    //*********************************************************************
+    // Constructor
+
+    public TransformTag() {
+        super();
+        init();
+    }
+
+
+    //*********************************************************************
+    // Tag logic
+
+    // evaluates expression and chains to parent
+    public int doStartTag() throws JspException {
+
+        // evaluate any expressions we were passed, once per invocation
+        evaluateExpressions();
+
+	// chain to the parent implementation
+	return super.doStartTag();
+    }
+
+
+    // Releases any resources we may have (or inherit)
+    public void release() {
+        super.release();
+        init();
+    }
+
+
+    //*********************************************************************
+    // Accessor methods
+
+    // for EL-based attribute
+    public void setXml(String xml_) {
+        this.xml_ = xml_;
+    }
+
+    // for EL-based attribute
+    public void setXmlSystemId(String xmlSystemId_) {
+        this.xmlSystemId_ = xmlSystemId_;
+    }
+
+    // for EL-based attribute
+    public void setXslt(String xslt_) {
+        this.xslt_ = xslt_;
+    }
+
+    // for EL-based attribute
+    public void setXsltSystemId(String xsltSystemId_) {
+        this.xsltSystemId_ = xsltSystemId_;
+    }
+
+    /* Removed for RI 0.5 
+     // for EL-based attribute
+     public void setTransformer(String transformer_) {
+         this.transformer_ = transformer_;
+     }
+    */
+
+    // for EL-based attribute
+    public void setResult(String result_) {
+        this.result_ = result_;
+    }
+
+
+    //*********************************************************************
+    // Private (utility) methods
+
+    // (re)initializes state (during release() or construction)
+    private void init() {
+        // null implies "no expression"
+	xml_ = xmlSystemId = xslt_ = xsltSystemId_ = result_ = null;
+    }
+
+    /* Evaluates expressions as necessary */
+    private void evaluateExpressions() throws JspException {
+        /* 
+         * Note: we don't check for type mismatches here; we assume
+         * the expression evaluator will return the expected type
+         * (by virtue of knowledge we give it about what that type is).
+         * A ClassCastException here is truly unexpected, so we let it
+         * propagate up.
+         */
+
+	xml = ExpressionUtil.evalNotNull(
+	    "transform", "xml", xml_, Object.class, this, pageContext);
+	xmlSystemId = (String) ExpressionUtil.evalNotNull(
+	    "transform", "xmlSystemId", xmlSystemId_, String.class,
+            this, pageContext);
+	xslt= ExpressionUtil.evalNotNull(
+	    "transform", "xslt", xslt_, Object.class, this,
+	    pageContext);
+	xsltSystemId = (String) ExpressionUtil.evalNotNull(
+	    "transform", "xsltSystemId", xsltSystemId_, String.class,
+	    this, pageContext);
+	result = (Result) ExpressionUtil.evalNotNull(
+	    "transform", "result", result_, Result.class, this, pageContext);
+
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/rt/core/ForEachTag.java b/standard/src/org/apache/taglibs/standard/tag/rt/core/ForEachTag.java
new file mode 100644
index 0000000..203a8c9
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/rt/core/ForEachTag.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.rt.core;
+
+import java.util.ArrayList;
+
+import javax.servlet.jsp.JspTagException;
+import javax.servlet.jsp.jstl.core.LoopTag;
+import javax.servlet.jsp.tagext.IterationTag;
+
+import org.apache.taglibs.standard.tag.common.core.ForEachSupport;
+
+/**
+ * <p>A handler for <forEach> that supports rtexprvalue-based
+ * attributes.</p>
+ *
+ * @author Shawn Bayern
+ */
+
+public class ForEachTag
+    extends ForEachSupport
+    implements LoopTag, IterationTag
+{
+
+    //*********************************************************************
+    // Accessor methods
+
+    // for tag attribute
+    public void setBegin(int begin) throws JspTagException {
+        this.beginSpecified = true;
+        this.begin = begin;
+        validateBegin();
+    }
+
+    // for tag attribute
+    public void setEnd(int end) throws JspTagException {
+        this.endSpecified = true;
+        this.end = end;
+        validateEnd();
+    }
+
+    // for tag attribute
+    public void setStep(int step) throws JspTagException {
+        this.stepSpecified = true;
+        this.step = step;
+        validateStep();
+    }
+
+    public void setItems(Object o) throws JspTagException {
+	// for null items, simulate an empty list
+	if (o == null)
+	    rawItems = new ArrayList();
+        else
+	    rawItems = o;
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/rt/core/ForTokensTag.java b/standard/src/org/apache/taglibs/standard/tag/rt/core/ForTokensTag.java
new file mode 100644
index 0000000..351089a
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/rt/core/ForTokensTag.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.rt.core;
+
+import javax.servlet.jsp.JspTagException;
+import javax.servlet.jsp.jstl.core.LoopTag;
+import javax.servlet.jsp.tagext.IterationTag;
+
+import org.apache.taglibs.standard.tag.common.core.ForTokensSupport;
+
+/**
+ * <p>A handler for <forTokens> that supports rtexprvalue-based
+ * attributes.</p>
+ *
+ * @author Shawn Bayern
+ */
+
+public class ForTokensTag
+    extends ForTokensSupport
+    implements LoopTag, IterationTag
+{
+
+    //*********************************************************************
+    // Accessor methods
+
+    // for tag attribute
+    public void setBegin(int begin) throws JspTagException {
+        this.beginSpecified = true;
+        this.begin = begin;
+        validateBegin();
+    }
+
+    // for tag attribute
+    public void setEnd(int end) throws JspTagException {
+        this.endSpecified = true;
+        this.end = end;
+        validateEnd();
+    }
+
+    // for tag attribute
+    public void setStep(int step) throws JspTagException {
+        this.stepSpecified = true;
+        this.step = step;
+        validateStep();
+    }
+
+    // stores the 'items' String we're passed
+    public void setItems(String s) throws JspTagException {
+        items = s;
+	// use the empty string to indicate "no iteration"
+        if (s == null)
+	    items = "";
+    }
+
+    // stores the 'delims' String we're passed
+    public void setDelims(String s) throws JspTagException {
+        delims = s;
+	// use the empty string to cause monolithic tokenization
+        if (s == null)
+	    delims = "";
+    }
+
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/rt/core/IfTag.java b/standard/src/org/apache/taglibs/standard/tag/rt/core/IfTag.java
new file mode 100644
index 0000000..555d210
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/rt/core/IfTag.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.rt.core;
+
+import javax.servlet.jsp.jstl.core.ConditionalTagSupport;
+
+/**
+ * <p>Tag handler for <if> in JSTL's rtexprvalue library.  Because
+ * of the support provided by the ConditionalTagSupport class, this
+ * tag is trivial enough not to require a separate base supporting class
+ * common to both libraries.</p>
+ *
+ * @author Shawn Bayern
+ */
+
+public class IfTag extends ConditionalTagSupport {
+
+    //*********************************************************************
+    // Constructor and lifecycle management
+
+    // initialize inherited and local state
+    public IfTag() {
+        super();
+        init();
+    }
+
+    // Releases any resources we may have (or inherit)
+    public void release() {
+        super.release();
+        init();
+    }
+
+
+    //*********************************************************************
+    // Supplied conditional logic
+
+    protected boolean condition() {
+        return test;
+    }
+
+
+    //*********************************************************************
+    // Private state
+
+    private boolean test;               // the value of the 'test' attribute
+
+
+    //*********************************************************************
+    // Accessors
+
+    // receives the tag's 'test' attribute
+    public void setTest(boolean test) {
+        this.test = test;
+    }
+
+
+    //*********************************************************************
+    // Private utility methods
+
+    // resets internal state
+    private void init() {
+        test = false;
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/rt/core/ImportTag.java b/standard/src/org/apache/taglibs/standard/tag/rt/core/ImportTag.java
new file mode 100644
index 0000000..174e8a0
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/rt/core/ImportTag.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.rt.core;
+
+import javax.servlet.jsp.JspTagException;
+
+import org.apache.taglibs.standard.tag.common.core.ImportSupport;
+
+/**
+ * <p>A handler for <import> that supports rtexprvalue-based
+ * attributes.</p>
+ *
+ * @author Shawn Bayern
+ */
+
+public class ImportTag extends ImportSupport {
+
+    //*********************************************************************
+    // Accessor methods
+
+    // for tag attribute
+    public void setUrl(String url) throws JspTagException {
+        this.url = url;
+    }
+
+    // for tag attribute
+    public void setContext(String context) throws JspTagException {
+        this.context = context;
+    }
+
+    // for tag attribute
+    public void setCharEncoding(String charEncoding) throws JspTagException {
+        this.charEncoding = charEncoding;
+    }
+
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/rt/core/OutTag.java b/standard/src/org/apache/taglibs/standard/tag/rt/core/OutTag.java
new file mode 100644
index 0000000..29f18d3
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/rt/core/OutTag.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.rt.core;
+
+import org.apache.taglibs.standard.tag.common.core.OutSupport;
+
+/**
+ * <p>Tag handler for <out> in JSTL's rtexprvalue library.</p>
+ *
+ * @author Shawn Bayern
+ */
+
+public class OutTag extends OutSupport {
+
+    //*********************************************************************
+    // Accessors
+       
+    // for tag attribute
+    public void setValue(Object value) {
+        this.value = value;
+    }
+      
+    // for tag attribute
+    public void setDefault(String def) {
+        this.def = def;
+    }
+        
+    // for tag attribute
+    public void setEscapeXml(boolean escapeXml) {
+        this.escapeXml = escapeXml;
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/rt/core/ParamTag.java b/standard/src/org/apache/taglibs/standard/tag/rt/core/ParamTag.java
new file mode 100644
index 0000000..7d0cca4
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/rt/core/ParamTag.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.rt.core;
+
+import javax.servlet.jsp.JspTagException;
+
+import org.apache.taglibs.standard.tag.common.core.ParamSupport;
+
+/**
+ * <p>A handler for <param> that supports rtexprvalue-based
+ * attributes.</p>
+ *
+ * @author Shawn Bayern
+ */
+
+public class ParamTag extends ParamSupport {
+
+    //*********************************************************************
+    // Accessor methods
+
+    // for tag attribute
+    public void setName(String name) throws JspTagException {
+        this.name = name;
+    }
+
+    // for tag attribute
+    public void setValue(String value) throws JspTagException {
+        this.value = value;
+    }
+
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/rt/core/RedirectTag.java b/standard/src/org/apache/taglibs/standard/tag/rt/core/RedirectTag.java
new file mode 100644
index 0000000..9dbf8b3
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/rt/core/RedirectTag.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.rt.core;
+
+import javax.servlet.jsp.JspTagException;
+
+import org.apache.taglibs.standard.tag.common.core.RedirectSupport;
+
+/**
+ * <p>A handler for <redirect> that supports rtexprvalue-based
+ * attributes.</p>
+ *
+ * @author Shawn Bayern
+ */
+
+public class RedirectTag extends RedirectSupport {
+
+    //*********************************************************************
+    // Accessor methods
+
+    // for tag attribute
+    public void setUrl(String url) throws JspTagException {
+        this.url = url;
+    }
+
+    // for tag attribute
+    public void setContext(String context) throws JspTagException {
+        this.context = context;
+    }
+
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/rt/core/SetTag.java b/standard/src/org/apache/taglibs/standard/tag/rt/core/SetTag.java
new file mode 100644
index 0000000..5714b5e
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/rt/core/SetTag.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.rt.core;
+
+import org.apache.taglibs.standard.tag.common.core.SetSupport;
+
+/**
+ * <p>Tag handler for <set> in JSTL's rtexprvalue library.</p>
+ *
+ * @author Shawn Bayern
+ */
+
+public class SetTag extends SetSupport {
+
+    //*********************************************************************
+    // Accessors
+
+    // for tag attribute
+    public void setValue(Object value) {
+        this.value = value;
+	this.valueSpecified = true;
+    }
+
+    // for tag attribute
+    public void setTarget(Object target) {
+        this.target = target;
+    }
+
+    // for tag attribute
+    public void setProperty(String property) {
+        this.property = property;
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/rt/core/UrlTag.java b/standard/src/org/apache/taglibs/standard/tag/rt/core/UrlTag.java
new file mode 100644
index 0000000..7a4054d
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/rt/core/UrlTag.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.rt.core;
+
+import javax.servlet.jsp.JspTagException;
+
+import org.apache.taglibs.standard.tag.common.core.UrlSupport;
+
+/**
+ * <p>A handler for <urlEncode> that supports rtexprvalue-based
+ * attributes.</p>
+ *
+ * @author Shawn Bayern
+ */
+
+public class UrlTag extends UrlSupport {
+
+    //*********************************************************************
+    // Accessor methods
+
+    // for tag attribute
+    public void setValue(String value) throws JspTagException {
+        this.value = value;
+    }
+
+    // for tag attribute
+    public void setContext(String context) throws JspTagException {
+        this.context = context;
+    }
+
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/rt/core/WhenTag.java b/standard/src/org/apache/taglibs/standard/tag/rt/core/WhenTag.java
new file mode 100644
index 0000000..332c51c
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/rt/core/WhenTag.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.rt.core;
+
+import org.apache.taglibs.standard.tag.common.core.WhenTagSupport;
+
+/**
+ * <p>Tag handler for <when> in JSTL's rtexprvalue library.</p>
+ *
+ * @author Shawn Bayern
+ */
+
+public class WhenTag extends WhenTagSupport {
+
+    //*********************************************************************
+    // Constructor and lifecycle management
+
+    // initialize inherited and local state
+    public WhenTag() {
+        super();
+        init();
+    }
+
+    // Releases any resources we may have (or inherit)
+    public void release() {
+        super.release();
+        init();
+    }
+
+
+    //*********************************************************************
+    // Supplied conditional logic
+
+    protected boolean condition() {
+        return test;
+    }
+
+
+    //*********************************************************************
+    // Private state
+
+    private boolean test;               // the value of the 'test' attribute
+
+
+    //*********************************************************************
+    // Accessors
+
+    // receives the tag's 'test' attribute
+    public void setTest(boolean test) {
+        this.test = test;
+    }
+
+
+    //*********************************************************************
+    // Private utility methods
+
+    // resets internal state
+    private void init() {
+        test = false;
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/rt/fmt/BundleTag.java b/standard/src/org/apache/taglibs/standard/tag/rt/fmt/BundleTag.java
new file mode 100644
index 0000000..598213e
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/rt/fmt/BundleTag.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.rt.fmt;
+
+import javax.servlet.jsp.JspTagException;
+
+import org.apache.taglibs.standard.tag.common.fmt.BundleSupport;
+
+/**
+ * <p>A handler for <bundle> that supports rtexprvalue-based
+ * attributes.</p>
+ *
+ * @author Jan Luehe
+ */
+
+public class BundleTag extends BundleSupport {
+
+    //*********************************************************************
+    // Accessor methods
+
+    // for tag attribute
+    public void setBasename(String basename) throws JspTagException {
+        this.basename = basename;
+    }
+
+    // for tag attribute
+    public void setPrefix(String prefix) throws JspTagException {
+        this.prefix = prefix;
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/rt/fmt/FormatDateTag.java b/standard/src/org/apache/taglibs/standard/tag/rt/fmt/FormatDateTag.java
new file mode 100644
index 0000000..6aac761
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/rt/fmt/FormatDateTag.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.rt.fmt;
+
+import java.util.Date;
+
+import javax.servlet.jsp.JspTagException;
+
+import org.apache.taglibs.standard.tag.common.fmt.FormatDateSupport;
+
+/**
+ * <p>A handler for <formatDate> that supports rtexprvalue-based
+ * attributes.</p>
+ *
+ * @author Jan Luehe
+ */
+
+public class FormatDateTag extends FormatDateSupport {
+
+    //*********************************************************************
+    // Accessor methods
+
+    // 'value' attribute
+    public void setValue(Date value) throws JspTagException {
+        this.value = value;
+    }
+
+    // 'type' attribute
+    public void setType(String type) throws JspTagException {
+        this.type = type;
+    }
+
+    // 'dateStyle' attribute
+    public void setDateStyle(String dateStyle) throws JspTagException {
+        this.dateStyle = dateStyle;
+    }
+
+    // 'timeStyle' attribute
+    public void setTimeStyle(String timeStyle) throws JspTagException {
+        this.timeStyle = timeStyle;
+    }
+
+    // 'pattern' attribute
+    public void setPattern(String pattern) throws JspTagException {
+        this.pattern = pattern;
+    }
+
+    // 'timeZone' attribute
+    public void setTimeZone(Object timeZone) throws JspTagException {
+        this.timeZone = timeZone;
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/rt/fmt/FormatNumberTag.java b/standard/src/org/apache/taglibs/standard/tag/rt/fmt/FormatNumberTag.java
new file mode 100644
index 0000000..b9a7d70
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/rt/fmt/FormatNumberTag.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.rt.fmt;
+
+import javax.servlet.jsp.JspTagException;
+
+import org.apache.taglibs.standard.tag.common.fmt.FormatNumberSupport;
+
+/**
+ * <p>A handler for <formatNumber> that supports rtexprvalue-based
+ * attributes.</p>
+ *
+ * @author Jan Luehe
+ */
+
+public class FormatNumberTag extends FormatNumberSupport {
+
+    //*********************************************************************
+    // Accessor methods
+
+    // 'value' attribute
+    public void setValue(Object value) throws JspTagException {
+        this.value = value;
+	this.valueSpecified = true;
+    }
+
+    // 'type' attribute
+    public void setType(String type) throws JspTagException {
+        this.type = type;
+    }
+
+    // 'pattern' attribute
+    public void setPattern(String pattern) throws JspTagException {
+        this.pattern = pattern;
+    }
+
+    // 'currencyCode' attribute
+    public void setCurrencyCode(String currencyCode) throws JspTagException {
+        this.currencyCode = currencyCode;
+    }
+
+    // 'currencySymbol' attribute
+    public void setCurrencySymbol(String currencySymbol)
+	throws JspTagException {
+        this.currencySymbol = currencySymbol;
+    }
+
+    // 'groupingUsed' attribute
+    public void setGroupingUsed(boolean isGroupingUsed)
+	throws JspTagException {
+        this.isGroupingUsed = isGroupingUsed;
+	this.groupingUsedSpecified = true;
+    }
+
+    // 'maxIntegerDigits' attribute
+    public void setMaxIntegerDigits(int maxDigits) throws JspTagException {
+        this.maxIntegerDigits = maxDigits;
+	this.maxIntegerDigitsSpecified = true;
+    }
+
+    // 'minIntegerDigits' attribute
+    public void setMinIntegerDigits(int minDigits) throws JspTagException {
+        this.minIntegerDigits = minDigits;
+	this.minIntegerDigitsSpecified = true;
+    }
+
+    // 'maxFractionDigits' attribute
+    public void setMaxFractionDigits(int maxDigits) throws JspTagException {
+        this.maxFractionDigits = maxDigits;
+	this.maxFractionDigitsSpecified = true;
+    }
+
+    // 'minFractionDigits' attribute
+    public void setMinFractionDigits(int minDigits) throws JspTagException {
+        this.minFractionDigits = minDigits;
+	this.minFractionDigitsSpecified = true;
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/rt/fmt/MessageTag.java b/standard/src/org/apache/taglibs/standard/tag/rt/fmt/MessageTag.java
new file mode 100644
index 0000000..ba99c02
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/rt/fmt/MessageTag.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.rt.fmt;
+
+import javax.servlet.jsp.JspTagException;
+import javax.servlet.jsp.jstl.fmt.LocalizationContext;
+
+import org.apache.taglibs.standard.tag.common.fmt.MessageSupport;
+
+/**
+ * <p>A handler for <message> that supports rtexprvalue-based
+ * attributes.</p>
+ *
+ * @author Jan Luehe
+ */
+
+public class MessageTag extends MessageSupport {
+
+    //*********************************************************************
+    // Accessor methods
+
+    // for tag attribute
+    public void setKey(String key) throws JspTagException {
+        this.keyAttrValue = key;
+	this.keySpecified = true;
+    }
+
+    // for tag attribute
+    public void setBundle(LocalizationContext locCtxt) throws JspTagException {
+        this.bundleAttrValue = locCtxt;
+        this.bundleSpecified = true;
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/rt/fmt/ParamTag.java b/standard/src/org/apache/taglibs/standard/tag/rt/fmt/ParamTag.java
new file mode 100644
index 0000000..8482ab1
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/rt/fmt/ParamTag.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.rt.fmt;
+
+import javax.servlet.jsp.JspTagException;
+
+import org.apache.taglibs.standard.tag.common.fmt.ParamSupport;
+
+/**
+ * <p>A handler for <param> that supports rtexprvalue-based
+ * message arguments.</p>
+ *
+ * @author Jan Luehe
+ */
+
+public class ParamTag extends ParamSupport {
+
+    //*********************************************************************
+    // Accessor methods
+
+    // for tag attribute
+    public void setValue(Object value) throws JspTagException {
+        this.value = value;
+	this.valueSpecified = true;
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/rt/fmt/ParseDateTag.java b/standard/src/org/apache/taglibs/standard/tag/rt/fmt/ParseDateTag.java
new file mode 100644
index 0000000..81a2016
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/rt/fmt/ParseDateTag.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.rt.fmt;
+
+import java.util.Locale;
+
+import javax.servlet.jsp.JspTagException;
+
+import org.apache.taglibs.standard.tag.common.fmt.ParseDateSupport;
+import org.apache.taglibs.standard.tag.common.fmt.SetLocaleSupport;
+
+/**
+ * <p>A handler for <parseDate> that supports rtexprvalue-based
+ * attributes.</p>
+ *
+ * @author Jan Luehe
+ */
+
+public class ParseDateTag extends ParseDateSupport {
+
+    //*********************************************************************
+    // Accessor methods
+
+    // 'value' attribute
+    public void setValue(String value) throws JspTagException {
+        this.value = value;
+	this.valueSpecified = true;
+    }
+
+    // 'type' attribute
+    public void setType(String type) throws JspTagException {
+        this.type = type;
+    }
+
+    // 'dateStyle' attribute
+    public void setDateStyle(String dateStyle) throws JspTagException {
+        this.dateStyle = dateStyle;
+    }
+
+    // 'timeStyle' attribute
+    public void setTimeStyle(String timeStyle) throws JspTagException {
+        this.timeStyle = timeStyle;
+    }
+
+    // 'pattern' attribute
+    public void setPattern(String pattern) throws JspTagException {
+        this.pattern = pattern;
+    }
+
+    // 'timeZone' attribute
+    public void setTimeZone(Object timeZone) throws JspTagException {
+        this.timeZone = timeZone;
+    }
+
+    // 'parseLocale' attribute
+    public void setParseLocale(Object loc) throws JspTagException {
+	if (loc != null) {
+	    if (loc instanceof Locale) {
+		this.parseLocale = (Locale) loc;
+	    } else {
+		if (!"".equals((String) loc)) {
+		    this.parseLocale = SetLocaleSupport.parseLocale((String)
+								    loc);
+		}
+	    }
+	}
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/rt/fmt/ParseNumberTag.java b/standard/src/org/apache/taglibs/standard/tag/rt/fmt/ParseNumberTag.java
new file mode 100644
index 0000000..001eabf
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/rt/fmt/ParseNumberTag.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.rt.fmt;
+
+import java.util.Locale;
+
+import javax.servlet.jsp.JspTagException;
+
+import org.apache.taglibs.standard.tag.common.fmt.ParseNumberSupport;
+import org.apache.taglibs.standard.tag.common.fmt.SetLocaleSupport;
+
+/**
+ * <p>A handler for <parseNumber> that supports rtexprvalue-based
+ * attributes.</p>
+ *
+ * @author Jan Luehe
+ */
+
+public class ParseNumberTag extends ParseNumberSupport {
+
+    //*********************************************************************
+    // Accessor methods
+
+    // 'value' attribute
+    public void setValue(String value) throws JspTagException {
+        this.value = value;
+	this.valueSpecified = true;
+    }
+
+    // 'type' attribute
+    public void setType(String type) throws JspTagException {
+        this.type = type;
+    }
+
+    // 'pattern' attribute
+    public void setPattern(String pattern) throws JspTagException {
+        this.pattern = pattern;
+    }
+
+    // 'parseLocale' attribute
+    public void setParseLocale(Object loc) throws JspTagException {
+	if (loc != null) {
+	    if (loc instanceof Locale) {
+		this.parseLocale = (Locale) loc;
+	    } else {
+		if (!"".equals((String) loc)) {
+		    this.parseLocale = SetLocaleSupport.parseLocale((String)
+								    loc);
+		}
+	    }
+	}
+    }
+
+    // 'integerOnly' attribute
+    public void setIntegerOnly(boolean isIntegerOnly) throws JspTagException {
+        this.isIntegerOnly = isIntegerOnly;
+	this.integerOnlySpecified = true;
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/rt/fmt/RequestEncodingTag.java b/standard/src/org/apache/taglibs/standard/tag/rt/fmt/RequestEncodingTag.java
new file mode 100644
index 0000000..7fbdafa
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/rt/fmt/RequestEncodingTag.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.rt.fmt;
+
+import javax.servlet.jsp.JspTagException;
+
+import org.apache.taglibs.standard.tag.common.fmt.RequestEncodingSupport;
+
+/**
+ * <p>A handler for <requestEncoding> that supports rtexprvalue-based
+ * attributes.</p>
+ *
+ * @author Jan Luehe
+ */
+
+public class RequestEncodingTag extends RequestEncodingSupport {
+
+    //*********************************************************************
+    // Accessor methods
+
+    // for tag attribute
+    public void setValue(String value) throws JspTagException {
+        this.value = value;
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/rt/fmt/SetBundleTag.java b/standard/src/org/apache/taglibs/standard/tag/rt/fmt/SetBundleTag.java
new file mode 100644
index 0000000..69d80a0
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/rt/fmt/SetBundleTag.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.rt.fmt;
+
+import javax.servlet.jsp.JspTagException;
+
+import org.apache.taglibs.standard.tag.common.fmt.SetBundleSupport;
+
+/**
+ * <p>A handler for <setBundle> that supports rtexprvalue-based
+ * attributes.</p>
+ *
+ * @author Jan Luehe
+ */
+
+public class SetBundleTag extends SetBundleSupport {
+
+    //*********************************************************************
+    // Accessor methods
+
+    // for tag attribute
+    public void setBasename(String basename) throws JspTagException {
+        this.basename = basename;
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/rt/fmt/SetLocaleTag.java b/standard/src/org/apache/taglibs/standard/tag/rt/fmt/SetLocaleTag.java
new file mode 100644
index 0000000..bae5a4f
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/rt/fmt/SetLocaleTag.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.rt.fmt;
+
+import javax.servlet.jsp.JspTagException;
+
+import org.apache.taglibs.standard.tag.common.fmt.SetLocaleSupport;
+
+/**
+ * <p>A handler for <setLocale> that supports rtexprvalue-based
+ * attributes.</p>
+ *
+ * @author Jan Luehe
+ */
+
+public class SetLocaleTag extends SetLocaleSupport {
+
+    //*********************************************************************
+    // Accessor methods
+
+    // for tag attribute
+    public void setValue(Object value) throws JspTagException {
+        this.value = value;
+    }
+
+    // for tag attribute
+    public void setVariant(String variant) throws JspTagException {
+        this.variant = variant;
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/rt/fmt/SetTimeZoneTag.java b/standard/src/org/apache/taglibs/standard/tag/rt/fmt/SetTimeZoneTag.java
new file mode 100644
index 0000000..7c8bc0e
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/rt/fmt/SetTimeZoneTag.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.rt.fmt;
+
+import javax.servlet.jsp.JspTagException;
+
+import org.apache.taglibs.standard.tag.common.fmt.SetTimeZoneSupport;
+
+/**
+ * <p>A handler for <setTimeZone> that supports rtexprvalue-based
+ * attributes.</p>
+ *
+ * @author Jan Luehe
+ */
+
+public class SetTimeZoneTag extends SetTimeZoneSupport {
+
+    //*********************************************************************
+    // Accessor methods
+
+    // for tag attribute
+    public void setValue(Object value) throws JspTagException {
+        this.value = value;
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/rt/fmt/TimeZoneTag.java b/standard/src/org/apache/taglibs/standard/tag/rt/fmt/TimeZoneTag.java
new file mode 100644
index 0000000..83fef19
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/rt/fmt/TimeZoneTag.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.rt.fmt;
+
+import javax.servlet.jsp.JspTagException;
+
+import org.apache.taglibs.standard.tag.common.fmt.TimeZoneSupport;
+
+/**
+ * <p>A handler for <timeZone> that supports rtexprvalue-based
+ * attributes.</p>
+ *
+ * @author Jan Luehe
+ */
+
+public class TimeZoneTag extends TimeZoneSupport {
+
+    //*********************************************************************
+    // Accessor methods
+
+    // for tag attribute
+    public void setValue(Object value) throws JspTagException {
+        this.value = value;
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/rt/sql/DateParamTag.java b/standard/src/org/apache/taglibs/standard/tag/rt/sql/DateParamTag.java
new file mode 100644
index 0000000..8466c49
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/rt/sql/DateParamTag.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.rt.sql;
+
+import java.util.Date;
+
+import org.apache.taglibs.standard.tag.common.sql.DateParamTagSupport;
+
+/**
+ * Subclass for the JSTL library with rtexprvalue support.
+ *
+ * @author Justyna Horwat
+ */
+public class DateParamTag extends DateParamTagSupport {
+    
+    public void setValue(Date value) {
+	this.value = value;
+    }
+
+    public void setType(String type) {
+	this.type = type;
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/rt/sql/ParamTag.java b/standard/src/org/apache/taglibs/standard/tag/rt/sql/ParamTag.java
new file mode 100644
index 0000000..96614a7
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/rt/sql/ParamTag.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.rt.sql;
+
+import org.apache.taglibs.standard.tag.common.sql.ParamTagSupport;
+
+/**
+ * Subclass for the JSTL library with rtexprvalue support.
+ *
+ * @author Hans Bergsten
+ */
+public class ParamTag extends ParamTagSupport {
+    
+    public void setValue(Object value) {
+	this.value = value;
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/rt/sql/QueryTag.java b/standard/src/org/apache/taglibs/standard/tag/rt/sql/QueryTag.java
new file mode 100644
index 0000000..eec491f
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/rt/sql/QueryTag.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.rt.sql;
+
+import org.apache.taglibs.standard.tag.common.sql.QueryTagSupport;
+
+/**
+ * Subclass for the JSTL library with rtexprvalue support.
+ *
+ * @author Hans Bergsten
+ * @author Justyna Horwat
+ */
+public class QueryTag extends QueryTagSupport {
+
+    //*********************************************************************
+    // Constructor
+
+    /**
+     * Constructs a new QueryTag.  As with TagSupport, subclasses
+     * should not provide other constructors and are expected to call
+     * the superclass constructor
+     */
+    public QueryTag() {
+        super();
+    }
+
+    //*********************************************************************
+    // Accessor methods
+    
+    public void setDataSource(Object dataSource) {
+	this.rawDataSource = dataSource;
+	this.dataSourceSpecified = true;
+    }
+
+    /**
+     * The index of the first row returned can be
+     * specified using startRow.
+     */
+    public void setStartRow(int startRow) {
+        this.startRow = startRow;
+    }
+
+    /**
+     * Query result can be limited by specifying
+     * the maximum number of rows returned.
+     */
+    public void setMaxRows(int maxRows) {
+        this.maxRows = maxRows;
+	this.maxRowsSpecified = true;
+    }
+
+    /**
+     * Setter method for the SQL statement to use for the
+     * query. The statement may contain parameter markers
+     * (question marks, ?). If so, the parameter values must
+     * be set using nested value elements.
+     */
+    public void setSql(String sql) {
+	this.sql = sql;
+    }
+
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/rt/sql/SetDataSourceTag.java b/standard/src/org/apache/taglibs/standard/tag/rt/sql/SetDataSourceTag.java
new file mode 100644
index 0000000..1c75b12
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/rt/sql/SetDataSourceTag.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.rt.sql;
+
+import org.apache.taglibs.standard.tag.common.sql.SetDataSourceTagSupport;
+
+/**
+ * <p>Tag handler for <Driver> in JSTL, used to create
+ * a simple DataSource for prototyping.</p>
+ * 
+ */
+public class SetDataSourceTag extends SetDataSourceTagSupport {
+
+    //*********************************************************************
+    // Accessor methods
+
+    public void setDataSource(Object dataSource) {
+	this.dataSource = dataSource;
+	this.dataSourceSpecified = true;
+    }
+
+    public void setDriver(String driverClassName) {
+	this.driverClassName = driverClassName;
+    }
+
+    public void setUrl(String jdbcURL) {
+	this.jdbcURL = jdbcURL;
+    }
+
+    public void setUser(String userName) {
+	this.userName = userName;
+    }
+
+    public void setPassword(String password) {
+	this.password = password;
+    }
+
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/rt/sql/TransactionTag.java b/standard/src/org/apache/taglibs/standard/tag/rt/sql/TransactionTag.java
new file mode 100644
index 0000000..165f61b
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/rt/sql/TransactionTag.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.rt.sql;
+
+import javax.servlet.jsp.JspException;
+
+import org.apache.taglibs.standard.tag.common.sql.TransactionTagSupport;
+
+/**
+ * Subclass for the JSTL library with rtexprvalue support.
+ *
+ * @author Hans Bergsten
+ */
+public class TransactionTag extends TransactionTagSupport {
+    private String isolationRT;
+    
+    //*********************************************************************
+    // Accessor methods
+
+
+    /**
+     * Setter method for the SQL DataSource. DataSource can be
+     * a String or a DataSource object.
+     */
+    public void setDataSource(Object dataSource) {
+	this.rawDataSource = dataSource;
+	this.dataSourceSpecified = true;
+    }
+
+    /**
+     * Setter method for the Transaction Isolation level.
+     */
+    public void setIsolation(String isolation) {
+	this.isolationRT = isolation;
+    }
+
+    public int doStartTag() throws JspException {
+	if (isolationRT != null)
+          super.setIsolation(isolationRT);
+        return super.doStartTag();
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/rt/sql/UpdateTag.java b/standard/src/org/apache/taglibs/standard/tag/rt/sql/UpdateTag.java
new file mode 100644
index 0000000..84a2d86
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/rt/sql/UpdateTag.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.rt.sql;
+
+import org.apache.taglibs.standard.tag.common.sql.UpdateTagSupport;
+
+/**
+ * Subclass for the JSTL library with rtexprvalue support.
+ *
+ * @author Hans Bergsten
+ */
+public class UpdateTag extends UpdateTagSupport {
+
+    //*********************************************************************
+    // Accessor methods
+
+    
+    /**
+     * Setter method for the SQL DataSource. DataSource can be
+     * a String or a DataSource object.
+     */
+    public void setDataSource(Object dataSource) {
+	this.rawDataSource = dataSource;
+	this.dataSourceSpecified = true;
+    }
+
+    /**
+     * Setter method for the SQL statement to use for the
+     * query. The statement may contain parameter markers
+     * (question marks, ?). If so, the parameter values must
+     * be set using nested value elements.
+     */
+    public void setSql(String sql) {
+	this.sql = sql;
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/rt/xml/ExprTag.java b/standard/src/org/apache/taglibs/standard/tag/rt/xml/ExprTag.java
new file mode 100644
index 0000000..01031e6
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/rt/xml/ExprTag.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.rt.xml;
+
+import org.apache.taglibs.standard.tag.common.xml.ExprSupport;
+
+/**
+ * <p>A handler for <out> that supports rtexprvalue-based
+ * attributes.</p>
+ *
+ * @author Shawn Bayern
+ */
+
+public class ExprTag extends ExprSupport {
+
+    //*********************************************************************
+    // Accessor methods
+
+    // for tag attribute
+    public void setEscapeXml(boolean escapeXml) {
+      this.escapeXml = escapeXml;
+    }
+
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/rt/xml/ParamTag.java b/standard/src/org/apache/taglibs/standard/tag/rt/xml/ParamTag.java
new file mode 100644
index 0000000..48a8075
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/rt/xml/ParamTag.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.rt.xml;
+
+import javax.servlet.jsp.JspTagException;
+
+import org.apache.taglibs.standard.tag.common.xml.ParamSupport;
+
+/**
+ * <p>A handler for <param> that supports rtexprvalue-based
+ * attributes.</p>
+ *
+ * @author Shawn Bayern
+ */
+
+public class ParamTag extends ParamSupport {
+
+    //*********************************************************************
+    // Accessor methods
+
+    // for tag attribute
+    public void setName(String name) throws JspTagException {
+        this.name = name;
+    }
+
+    // for tag attribute
+    public void setValue(Object value) throws JspTagException {
+        this.value = value;
+    }
+
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/rt/xml/ParseTag.java b/standard/src/org/apache/taglibs/standard/tag/rt/xml/ParseTag.java
new file mode 100644
index 0000000..44b5e91
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/rt/xml/ParseTag.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.rt.xml;
+
+import javax.servlet.jsp.JspTagException;
+
+import org.apache.taglibs.standard.tag.common.xml.ParseSupport;
+import org.xml.sax.XMLFilter;
+
+/**
+ * <p>A handler for <parse> that supports rtexprvalue-based
+ * attributes.</p>
+ *
+ * @author Shawn Bayern
+ */
+
+public class ParseTag extends ParseSupport {
+
+    //*********************************************************************
+    // Accessor methods
+
+    // Deprecated as of JSTL 1.1
+    // for tag attribute
+    public void setXml(Object xml) throws JspTagException {
+        this.xml = xml;
+    }
+
+    // 'doc' replaces 'xml' as of JSTL 1.1
+    public void setDoc(Object xml) throws JspTagException {
+        this.xml = xml;
+    }
+
+    public void setSystemId(String systemId) throws JspTagException {
+	this.systemId = systemId;
+    }
+
+    // for tag attribute
+    public void setFilter(XMLFilter filter) throws JspTagException {
+	this.filter = filter;
+    }
+
+}
diff --git a/standard/src/org/apache/taglibs/standard/tag/rt/xml/TransformTag.java b/standard/src/org/apache/taglibs/standard/tag/rt/xml/TransformTag.java
new file mode 100644
index 0000000..7896df2
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tag/rt/xml/TransformTag.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tag.rt.xml;
+
+import javax.servlet.jsp.JspTagException;
+import javax.xml.transform.Result;
+
+import org.apache.taglibs.standard.tag.common.xml.TransformSupport;
+
+/**
+ * <p>A handler for <transform> that supports rtexprvalue-based
+ * attributes.</p>
+ *
+ * @author Shawn Bayern
+ */
+
+public class TransformTag extends TransformSupport {
+
+    //*********************************************************************
+    // Accessor methods
+
+    // Deprecated as of JSTL 1.1
+    // for tag attribute
+    public void setXml(Object xml) throws JspTagException {
+        this.xml = xml;
+    }
+
+    // 'doc' replaces 'xml' as of JSTL 1.1
+    public void setDoc(Object xml) throws JspTagException {
+        this.xml = xml;
+    }
+
+    // Deprecated as of JSTL 1.1
+    // for tag attribute
+    public void setXmlSystemId(String xmlSystemId) throws JspTagException {
+        this.xmlSystemId = xmlSystemId;
+    }
+
+    // 'docSystemId' replaces 'xmlSystemId' as of JSTL 1.1
+    public void setDocSystemId(String xmlSystemId) throws JspTagException {
+        this.xmlSystemId = xmlSystemId;
+    }
+
+    // for tag attribute
+    public void setXslt(Object xslt) throws JspTagException {
+        this.xslt = xslt;
+    }
+
+    // for tag attribute
+    public void setXsltSystemId(String xsltSystemId) throws JspTagException {
+        this.xsltSystemId = xsltSystemId;
+    }
+
+    // for tag attribute
+    public void setResult(Result result) throws JspTagException {
+        this.result = result;
+    }
+
+}
diff --git a/standard/src/org/apache/taglibs/standard/tei/DeclareTEI.java b/standard/src/org/apache/taglibs/standard/tei/DeclareTEI.java
new file mode 100644
index 0000000..5d1e129
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tei/DeclareTEI.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tei;
+
+import javax.servlet.jsp.tagext.TagData;
+import javax.servlet.jsp.tagext.TagExtraInfo;
+import javax.servlet.jsp.tagext.VariableInfo;
+
+/**
+ * <p>An implementation of TagExtraInfo provided for <declare>.
+ * We simply set up a scripting variable for the ID and value that
+ * <declare> already stored.  For EA2, DefineTEI *always* declares
+ * the variable; no option is given via a tag attribute.  Visibility is
+ * always AT_END.</p>
+ *
+ * @author Shawn Bayern
+ */
+public class DeclareTEI extends TagExtraInfo {
+
+    // purposely inherit JavaDoc and semantics from TagExtraInfo
+    public VariableInfo[] getVariableInfo(TagData data) {
+        // construct the relevant VariableInfo object
+        VariableInfo id = new VariableInfo(
+            data.getAttributeString("id"),
+            data.getAttributeString("type") == null ?
+		"java.lang.Object" : data.getAttributeString("type"),
+            true,
+            VariableInfo.AT_END);
+        return new VariableInfo[] { id };
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tei/ForEachTEI.java b/standard/src/org/apache/taglibs/standard/tei/ForEachTEI.java
new file mode 100644
index 0000000..b782de1
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tei/ForEachTEI.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tei;
+
+import javax.servlet.jsp.tagext.TagData;
+import javax.servlet.jsp.tagext.TagExtraInfo;
+
+/**
+ * <p>An implementation of TagExtraInfo that implements validation for
+ * ForEachTag's attributes</p>
+ *
+ * @author Shawn Bayern
+ */
+public class ForEachTEI extends TagExtraInfo {
+
+    final private static String ITEMS = "items";
+    final private static String BEGIN = "begin";
+    final private static String END = "end";
+
+    /*
+     * Currently implements the following rules:
+     * 
+     * - If 'items' is not specified, 'begin' and 'end' must be
+     */
+    public boolean isValid(TagData us) {
+        if (!Util.isSpecified(us, ITEMS))
+            if (!Util.isSpecified(us, BEGIN) || !(Util.isSpecified(us, END)))
+                return false;
+        return true;
+    }
+
+}
diff --git a/standard/src/org/apache/taglibs/standard/tei/ImportTEI.java b/standard/src/org/apache/taglibs/standard/tei/ImportTEI.java
new file mode 100644
index 0000000..4a90e16
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tei/ImportTEI.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tei;
+
+import javax.servlet.jsp.tagext.TagData;
+import javax.servlet.jsp.tagext.TagExtraInfo;
+
+/**
+ * <p>An implementation of TagExtraInfo that implements validation for
+ * <c:import>'s attributes</p>
+ *
+ * @author Shawn Bayern
+ */
+public class ImportTEI extends TagExtraInfo {
+
+    final private static String VAR = "var";
+    final private static String VAR_READER = "varReader";
+
+    public boolean isValid(TagData us) {
+	// don't allow both VAR and VAR_READER, together
+	if (Util.isSpecified(us, VAR) && Util.isSpecified(us, VAR_READER))
+	    return false;
+
+        return true;
+    }
+
+}
diff --git a/standard/src/org/apache/taglibs/standard/tei/Util.java b/standard/src/org/apache/taglibs/standard/tei/Util.java
new file mode 100644
index 0000000..bcd32c4
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tei/Util.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tei;
+
+import javax.servlet.jsp.tagext.TagData;
+
+/**
+ * <p>Utilities in support of TagExtraInfo classes.</p>
+ *
+ * @author Shawn Bayern
+ */
+public class Util {
+
+    /**
+     * Returns true if the given attribute name is specified, false otherwise.
+     */
+    public static boolean isSpecified(TagData data, String attributeName) {
+        return (data.getAttribute(attributeName) != null);
+    }
+
+}
diff --git a/standard/src/org/apache/taglibs/standard/tei/XmlParseTEI.java b/standard/src/org/apache/taglibs/standard/tei/XmlParseTEI.java
new file mode 100644
index 0000000..e028217
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tei/XmlParseTEI.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tei;
+
+import javax.servlet.jsp.tagext.TagData;
+import javax.servlet.jsp.tagext.TagExtraInfo;
+
+/**
+ * <p>An implementation of TagExtraInfo that implements validation for
+ * <x:parse>'s attributes</p>
+ *
+ * @author Shawn Bayern
+ */
+public class XmlParseTEI extends TagExtraInfo {
+
+    final private static String VAR = "var";
+    final private static String VAR_DOM = "varDom";
+    final private static String SCOPE = "scope";
+    final private static String SCOPE_DOM = "scopeDom";
+
+    public boolean isValid(TagData us) {
+	// must have no more than one of VAR and VAR_DOM ...
+	if (Util.isSpecified(us, VAR) && Util.isSpecified(us, VAR_DOM))
+	    return false;
+
+	// ... and must have no less than one of VAR and VAR_DOM
+	if (!(Util.isSpecified(us, VAR) || Util.isSpecified(us, VAR_DOM)))
+	    return false;
+
+	// When either 'scope' is specified, its 'var' must be specified
+	if (Util.isSpecified(us, SCOPE) && !Util.isSpecified(us, VAR))
+	    return false;
+	if (Util.isSpecified(us, SCOPE_DOM) && !Util.isSpecified(us, VAR_DOM))
+	    return false;
+
+        return true;
+    }
+
+}
diff --git a/standard/src/org/apache/taglibs/standard/tei/XmlTransformTEI.java b/standard/src/org/apache/taglibs/standard/tei/XmlTransformTEI.java
new file mode 100644
index 0000000..bec838a
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tei/XmlTransformTEI.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tei;
+
+import javax.servlet.jsp.tagext.TagData;
+import javax.servlet.jsp.tagext.TagExtraInfo;
+
+/**
+ * <p>An implementation of TagExtraInfo that implements validation for
+ * <x:transform>'s attributes</p>
+ *
+ * @author Shawn Bayern
+ */
+public class XmlTransformTEI extends TagExtraInfo {
+
+    final private static String XSLT = "xslt";
+    final private static String RESULT = "result";
+    final private static String VAR = "var";
+
+    public boolean isValid(TagData us) {
+	// require XSLT
+	if (!Util.isSpecified(us, XSLT))
+	    return false;
+
+	// disallow both VAR and RESULT
+	if (Util.isSpecified(us, VAR) && Util.isSpecified(us, RESULT))
+	    return false;
+        return true;
+    }
+
+}
diff --git a/standard/src/org/apache/taglibs/standard/tlv/JstlBaseTLV.java b/standard/src/org/apache/taglibs/standard/tlv/JstlBaseTLV.java
new file mode 100644
index 0000000..e2d6092
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tlv/JstlBaseTLV.java
@@ -0,0 +1,337 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tlv;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Set;
+import java.util.StringTokenizer;
+import java.util.Vector;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.tagext.PageData;
+import javax.servlet.jsp.tagext.TagData;
+import javax.servlet.jsp.tagext.TagLibraryValidator;
+import javax.servlet.jsp.tagext.ValidationMessage;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import org.apache.taglibs.standard.lang.support.ExpressionEvaluator;
+import org.apache.taglibs.standard.lang.support.ExpressionEvaluatorManager;
+import org.apache.taglibs.standard.resources.Resources;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+/**
+ * <p>A base class to support SAX-based validation in JSTL.</p>
+ * 
+ * @author Shawn Bayern
+ */
+public abstract class JstlBaseTLV extends TagLibraryValidator {
+
+    //*********************************************************************
+    // Implementation Overview
+
+    /*
+     * We essentially just run the page through a SAX parser, handling
+     * the callbacks that interest us.  The SAX parser is supplied by
+     * subclasses using the protected getHandler() method.
+     */
+
+    protected abstract DefaultHandler getHandler();
+
+
+    //*********************************************************************
+    // Constants
+
+    // parameter names
+    private final String EXP_ATT_PARAM = "expressionAttributes";
+
+    // attributes
+    protected static final String VAR = "var";
+    protected static final String SCOPE = "scope";  
+
+    //scopes
+    protected static final String PAGE_SCOPE = "page";        
+    protected static final String REQUEST_SCOPE = "request";  
+    protected static final String SESSION_SCOPE = "session";  
+    protected static final String APPLICATION_SCOPE = "application";
+
+    // Relevant URIs
+    protected final String JSP = "http://java.sun.com/JSP/Page"; 
+    
+    // types of sub-classes - used on method validate()
+    private   static final int TYPE_UNDEFINED = 0;
+    protected static final int TYPE_CORE = 1;
+    protected static final int TYPE_FMT = 2;
+    protected static final int TYPE_SQL = 3;
+    protected static final int TYPE_XML = 4;
+
+    // which tlv is being validated
+    private int tlvType = TYPE_UNDEFINED;
+
+    //*********************************************************************
+    // Validation and configuration state (protected)
+
+    protected String uri;			// our taglib's uri (as passed by JSP container on XML View)
+    protected String prefix;			// our taglib's prefix
+    protected Vector messageVector;		// temporary error messages
+    protected Map config;			// configuration (Map of Sets)
+    protected boolean failed;			// have we failed >0 times?
+    protected String lastElementId;		// the last element we've seen
+
+    //*********************************************************************
+    // Constructor and lifecycle management
+
+    public JstlBaseTLV() {
+	super();
+	init();
+    }
+
+    private void init() {
+	messageVector = null;
+	prefix = null;
+	config = null;
+    }
+
+    public void release() {
+	super.release();
+	init();
+    }
+    
+
+    //*********************************************************************
+    // Validation entry point - this method is called by the sub-classes to 
+    // do the validation.
+
+    public synchronized ValidationMessage[] validate(
+	    int type, String prefix, String uri, PageData page) {
+	try {
+	    this.tlvType = type;
+	    this.uri = uri;
+	    // initialize
+	    messageVector = new Vector();
+
+	    // save the prefix
+	    this.prefix = prefix;
+
+	    // parse parameters if necessary
+	    try {
+		if (config == null)
+		    configure((String) getInitParameters().get(EXP_ATT_PARAM));
+	    } catch (NoSuchElementException ex) {
+		// parsing error
+	        return vmFromString(
+		    Resources.getMessage("TLV_PARAMETER_ERROR",
+			EXP_ATT_PARAM));
+	    }
+
+	    // get a handler
+	    DefaultHandler h = getHandler();
+
+	    // parse the page
+	    SAXParserFactory f = SAXParserFactory.newInstance();
+	    f.setValidating(false);
+	    f.setNamespaceAware(true);
+	    SAXParser p = f.newSAXParser();
+	    p.parse(page.getInputStream(), h);
+
+	    if (messageVector.size() == 0)
+		return null;
+	    else
+		return vmFromVector(messageVector);
+
+	} catch (SAXException ex) {
+	    return vmFromString(ex.toString());
+	} catch (ParserConfigurationException ex) {
+	    return vmFromString(ex.toString());
+	} catch (IOException ex) {
+	    return vmFromString(ex.toString());
+	}
+    }
+
+    //*********************************************************************
+    // Protected utility functions
+
+    // delegate validation to the appropriate expression language
+    protected String validateExpression(
+	    String elem, String att, String expr) {
+
+	// let's just use the cache kept by the ExpressionEvaluatorManager
+	ExpressionEvaluator current;
+	try {
+	    current =
+	        ExpressionEvaluatorManager.getEvaluatorByName(
+                  ExpressionEvaluatorManager.EVALUATOR_CLASS);
+	} catch (JspException ex) {
+	    // (using JspException here feels ugly, but it's what EEM uses)
+	    return ex.getMessage();
+	}
+	
+	String response = current.validate(att, expr);
+	if (response == null)
+	    return response;
+	else
+	    return "tag = '" + elem + "' / attribute = '" + att + "': "
+		+ response;
+    }
+
+    // utility methods to help us match elements in our tagset
+    protected boolean isTag(String tagUri,
+			    String tagLn,
+			    String matchUri,
+			    String matchLn) {
+	if (tagUri == null
+	        || tagLn == null
+		|| matchUri == null
+		|| matchLn == null)
+	    return false;
+        // match beginning of URI since some suffix *_rt tags can
+        // be nested in EL enabled tags as defined by the spec
+        if (tagUri.length() > matchUri.length()) {
+            return (tagUri.startsWith(matchUri) && tagLn.equals(matchLn));
+        } else {
+            return (matchUri.startsWith(tagUri) && tagLn.equals(matchLn));
+        }
+    }
+
+    protected boolean isJspTag(String tagUri, String tagLn, String target) {
+        return isTag(tagUri, tagLn, JSP, target);
+    }
+
+    private boolean isTag( int type, String tagUri, String tagLn, String target) {
+        return ( this.tlvType == type && isTag(tagUri, tagLn, this.uri, target) );
+    }
+
+    protected boolean isCoreTag(String tagUri, String tagLn, String target) {
+	return isTag( TYPE_CORE, tagUri, tagLn, target );
+    }
+
+    protected boolean isFmtTag(String tagUri, String tagLn, String target) {
+	return isTag( TYPE_FMT, tagUri, tagLn, target );
+    }
+
+    protected boolean isSqlTag(String tagUri, String tagLn, String target) {
+	return isTag( TYPE_SQL, tagUri, tagLn, target );
+    }
+
+    protected boolean isXmlTag(String tagUri, String tagLn, String target) {
+	return isTag( TYPE_XML, tagUri, tagLn, target );
+    }
+
+    // utility method to determine if an attribute exists
+    protected boolean hasAttribute(Attributes a, String att) {
+        return (a.getValue(att) != null);
+    }
+
+    /*
+     * method to assist with failure [ as if it's not easy enough
+     * already :-) ]
+     */
+    protected void fail(String message) {
+        failed = true;
+        messageVector.add(new ValidationMessage(lastElementId, message));
+    }
+
+    // returns true if the given attribute name is specified, false otherwise
+    protected boolean isSpecified(TagData data, String attributeName) {
+        return (data.getAttribute(attributeName) != null);
+    }
+
+    // returns true if the 'scope' attribute is valid
+    protected boolean hasNoInvalidScope(Attributes a) {
+        String scope = a.getValue(SCOPE);
+
+	if ((scope != null)
+	    && !scope.equals(PAGE_SCOPE)
+	    && !scope.equals(REQUEST_SCOPE)
+	    && !scope.equals(SESSION_SCOPE)
+	    && !scope.equals(APPLICATION_SCOPE))
+	    return false;
+
+        return true;
+    }
+
+    // returns true if the 'var' attribute is empty
+    protected boolean hasEmptyVar(Attributes a) {
+	if ("".equals(a.getValue(VAR)))
+	    return true;
+	return false;
+    }
+
+    // returns true if the 'scope' attribute is present without 'var'
+    protected boolean hasDanglingScope(Attributes a) {
+	return (a.getValue(SCOPE) != null && a.getValue(VAR) == null);
+    }
+
+    // retrieves the local part of a QName
+    protected String getLocalPart(String qname) {
+	int colon = qname.indexOf(":");
+	if (colon == -1)
+	    return qname;
+	else
+	    return qname.substring(colon + 1);
+    }
+
+    //*********************************************************************
+    // Miscellaneous utility functions
+
+    // parses our configuration parameter for element:attribute pairs
+    private void configure(String info) {
+        // construct our configuration map
+	config = new HashMap();
+
+	// leave the map empty if we have nothing to configure
+	if (info == null)
+	    return;
+
+	// separate parameter into space-separated tokens and store them
+	StringTokenizer st = new StringTokenizer(info);
+	while (st.hasMoreTokens()) {
+	    String pair = st.nextToken();
+	    StringTokenizer pairTokens = new StringTokenizer(pair, ":");
+	    String element = pairTokens.nextToken();
+	    String attribute = pairTokens.nextToken();
+	    Object atts = config.get(element);
+	    if (atts == null) {
+	        atts = new HashSet();
+	        config.put(element, atts);
+	    }
+	    ((Set) atts).add(attribute);
+	}
+    }
+
+    // constructs a ValidationMessage[] from a single String and no ID
+    static ValidationMessage[] vmFromString(String message) {
+	return new ValidationMessage[] {
+	    new ValidationMessage(null, message)
+	};
+    }
+
+    // constructs a ValidationMessage[] from a ValidationMessage Vector
+    static ValidationMessage[] vmFromVector(Vector v) {
+	ValidationMessage[] vm = new ValidationMessage[v.size()];
+	for (int i = 0; i < vm.length; i++)
+	   vm[i] = (ValidationMessage) v.get(i);
+	return vm;
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tlv/JstlCoreTLV.java b/standard/src/org/apache/taglibs/standard/tlv/JstlCoreTLV.java
new file mode 100644
index 0000000..2ef0706
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tlv/JstlCoreTLV.java
@@ -0,0 +1,326 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tlv;
+
+import java.util.Set;
+import java.util.Stack;
+
+import javax.servlet.jsp.tagext.PageData;
+import javax.servlet.jsp.tagext.ValidationMessage;
+
+import org.apache.taglibs.standard.resources.Resources;
+import org.xml.sax.Attributes;
+import org.xml.sax.helpers.DefaultHandler;
+
+/**
+ * <p>A SAX-based TagLibraryValidator for the core JSTL tag library.
+ * Currently implements the following checks:</p>
+ * 
+ * <ul>
+ *   <li>Expression syntax validation.
+ *   <li>Choose / when / otherwise constraints</li>
+ *   <li>Tag bodies that must either be empty or non-empty given
+ *      particular attributes.  (E.g., <set> cannot have a body when
+ *      'value' is specified; it *must* have a body otherwise.)  For
+ *      these purposes, "having a body" refers to non-whitespace
+ *      content inside the tag.</li>
+ *   <li>Other minor constraints.</li>
+ * </ul>
+ * 
+ * @author Shawn Bayern
+ */
+public class JstlCoreTLV extends JstlBaseTLV {
+
+    //*********************************************************************
+    // Implementation Overview
+
+    /*
+     * We essentially just run the page through a SAX parser, handling
+     * the callbacks that interest us.  We collapse <jsp:text> elements
+     * into the text they contain, since this simplifies processing
+     * somewhat.  Even a quick glance at the implementation shows its
+     * necessary, tree-oriented nature:  multiple Stacks, an understanding
+     * of 'depth', and so on all are important as we recover necessary
+     * state upon each callback.  This TLV demonstrates various techniques,
+     * from the general "how do I use a SAX parser for a TLV?" to
+     * "how do I read my init parameters and then validate?"  But also,
+     * the specific SAX methodology was kept as general as possible to
+     * allow for experimentation and flexibility.
+     */
+
+
+    //*********************************************************************
+    // Constants
+
+    // tag names
+    private final String CHOOSE = "choose";
+    private final String WHEN = "when";
+    private final String OTHERWISE = "otherwise";
+    private final String EXPR = "out";
+    private final String SET = "set";
+    private final String IMPORT = "import";
+    private final String URL = "url";
+    private final String REDIRECT = "redirect";
+    private final String PARAM = "param";
+    // private final String EXPLANG = "expressionLanguage";
+    private final String TEXT = "text";
+
+    // attribute names
+    private final String VALUE = "value";
+    private final String DEFAULT = "default";
+    private final String VAR_READER = "varReader";
+
+    // alternative identifiers for tags
+    private final String IMPORT_WITH_READER = "import varReader=''";
+    private final String IMPORT_WITHOUT_READER = "import var=''";
+
+
+    //*********************************************************************
+    // set its type and delegate validation to super-class
+    public  ValidationMessage[] validate(
+	    String prefix, String uri, PageData page) {
+	return super.validate( TYPE_CORE, prefix, uri, page );
+    }
+
+
+    //*********************************************************************
+    // Contract fulfillment
+
+    protected DefaultHandler getHandler() {
+	return new Handler();
+    }
+
+
+    //*********************************************************************
+    // SAX event handler
+
+    /** The handler that provides the base of our implementation. */
+    private class Handler extends DefaultHandler {
+
+	// parser state
+	private int depth = 0;
+	private Stack chooseDepths = new Stack();
+	private Stack chooseHasOtherwise = new Stack();
+	private Stack chooseHasWhen = new Stack();
+        private Stack urlTags = new Stack();
+	private String lastElementName = null;
+	private boolean bodyNecessary = false;
+	private boolean bodyIllegal = false;
+
+	// process under the existing context (state), then modify it
+	public void startElement(
+	        String ns, String ln, String qn, Attributes a) {
+
+	    // substitute our own parsed 'ln' if it's not provided
+	    if (ln == null)
+		ln = getLocalPart(qn);
+
+	    // for simplicity, we can ignore <jsp:text> for our purposes
+	    // (don't bother distinguishing between it and its characters)
+	    if (isJspTag(ns, ln, TEXT))
+		return;
+
+	    // check body-related constraint
+	    if (bodyIllegal)
+		fail(Resources.getMessage("TLV_ILLEGAL_BODY", lastElementName));
+
+	    // validate expression syntax if we need to
+	    Set expAtts;
+	    if (qn.startsWith(prefix + ":")
+		    && (expAtts = (Set) config.get(ln)) != null) {
+		for (int i = 0; i < a.getLength(); i++) {
+		    String attName = a.getLocalName(i);
+		    if (expAtts.contains(attName)) {
+			String vMsg =
+			    validateExpression(
+				ln,
+				attName,
+				a.getValue(i));
+			if (vMsg != null)
+			    fail(vMsg);
+		    }
+		}
+	    }
+
+            // validate attributes
+            if (qn.startsWith(prefix + ":") && !hasNoInvalidScope(a))
+                fail(Resources.getMessage("TLV_INVALID_ATTRIBUTE",
+                    SCOPE, qn, a.getValue(SCOPE))); 
+	    if (qn.startsWith(prefix + ":") && hasEmptyVar(a))
+		fail(Resources.getMessage("TLV_EMPTY_VAR", qn));
+	    if (qn.startsWith(prefix + ":") && hasDanglingScope(a))
+		fail(Resources.getMessage("TLV_DANGLING_SCOPE", qn));
+
+	    // check invariants for <choose>
+	    if (chooseChild()) {
+		// mark <choose> for the first the first <when>
+		if (isCoreTag(ns, ln, WHEN)) {
+		    chooseHasWhen.pop();
+		    chooseHasWhen.push(Boolean.TRUE);
+		}
+
+		// ensure <choose> has the right children
+		if(!isCoreTag(ns, ln, WHEN) && !isCoreTag(ns, ln, OTHERWISE)) {
+		    fail(Resources.getMessage("TLV_ILLEGAL_CHILD_TAG",
+			prefix, CHOOSE, qn));
+		}
+
+		// make sure <otherwise> is the last tag
+		if (((Boolean) chooseHasOtherwise.peek()).booleanValue()) {
+		   fail(Resources.getMessage("TLV_ILLEGAL_ORDER",
+			qn, prefix, OTHERWISE, CHOOSE));
+		}
+		if (isCoreTag(ns, ln, OTHERWISE)) {
+		    chooseHasOtherwise.pop();
+		    chooseHasOtherwise.push(Boolean.TRUE);
+		}
+
+	    }
+
+	    // check constraints for <param> vis-a-vis URL-related tags
+	    if (isCoreTag(ns, ln, PARAM)) {
+		// no <param> outside URL tags.
+		if (urlTags.empty() || urlTags.peek().equals(PARAM))
+		    fail(Resources.getMessage("TLV_ILLEGAL_ORPHAN", PARAM));
+
+		// no <param> where the most recent <import> has a reader
+		if (!urlTags.empty() &&
+			urlTags.peek().equals(IMPORT_WITH_READER))
+		    fail(Resources.getMessage("TLV_ILLEGAL_PARAM",
+			prefix, PARAM, IMPORT, VAR_READER));
+	    } else {
+		// tag ISN'T <param>, so it's illegal under non-reader <import>
+		if (!urlTags.empty()
+			&& urlTags.peek().equals(IMPORT_WITHOUT_READER))
+		    fail(Resources.getMessage("TLV_ILLEGAL_CHILD_TAG",
+			prefix, IMPORT, qn));
+	    }
+
+	    // now, modify state
+
+	    // we're a choose, so record new choose-specific state
+	    if (isCoreTag(ns, ln, CHOOSE)) {
+		chooseDepths.push(new Integer(depth));
+		chooseHasWhen.push(Boolean.FALSE);
+		chooseHasOtherwise.push(Boolean.FALSE);
+	    }
+
+	    // if we're introducing a URL-related tag, record it
+	    if (isCoreTag(ns, ln, IMPORT)) {
+		if (hasAttribute(a, VAR_READER))
+		    urlTags.push(IMPORT_WITH_READER);
+		else
+		    urlTags.push(IMPORT_WITHOUT_READER);
+	    } else if (isCoreTag(ns, ln, PARAM))
+		urlTags.push(PARAM);
+	    else if (isCoreTag(ns, ln, REDIRECT))
+		urlTags.push(REDIRECT);
+	    else if (isCoreTag(ns, ln, URL))
+		urlTags.push(URL);
+
+	    // set up a check against illegal attribute/body combinations
+	    bodyIllegal = false;
+	    bodyNecessary = false;
+	    if (isCoreTag(ns, ln, EXPR)) {
+		if (hasAttribute(a, DEFAULT))
+		    bodyIllegal = true;
+	    } else if (isCoreTag(ns, ln, SET)) {
+		if (hasAttribute(a, VALUE))
+		    bodyIllegal = true;
+		// else
+		//    bodyNecessary = true;
+	    }
+
+	    // record the most recent tag (for error reporting)
+	    lastElementName = qn;
+	    lastElementId = a.getValue(JSP, "id");
+
+	    // we're a new element, so increase depth
+	    depth++;
+	}
+
+	public void characters(char[] ch, int start, int length) {
+
+	    bodyNecessary = false;		// body is no longer necessary!
+
+	    // ignore strings that are just whitespace
+	    String s = new String(ch, start, length).trim();
+	    if (s.equals(""))
+		return;
+
+	    // check and update body-related constraints
+	    if (bodyIllegal)
+		fail(Resources.getMessage("TLV_ILLEGAL_BODY", lastElementName));
+	    if (!urlTags.empty()
+		    && urlTags.peek().equals(IMPORT_WITHOUT_READER)) {
+		// we're in an <import> without a Reader; nothing but
+		// <param> is allowed
+		fail(Resources.getMessage("TLV_ILLEGAL_BODY",
+		    prefix + ":" + IMPORT));
+	    }
+
+	    // make sure <choose> has no non-whitespace text
+	    if (chooseChild()) {
+		String msg = 
+		    Resources.getMessage("TLV_ILLEGAL_TEXT_BODY",
+			prefix, CHOOSE,
+			(s.length() < 7 ? s : s.substring(0,7)));
+		fail(msg);
+	    }
+	}
+
+	public void endElement(String ns, String ln, String qn) {
+
+	    // consistently, we ignore JSP_TEXT
+	    if (isJspTag(ns, ln, TEXT))
+		return;
+
+	    // handle body-related invariant
+	    if (bodyNecessary)
+		fail(Resources.getMessage("TLV_MISSING_BODY",
+		    lastElementName));
+	    bodyIllegal = false;	// reset: we've left the tag
+
+	    // update <choose>-related state
+	    if (isCoreTag(ns, ln, CHOOSE)) {
+		Boolean b = (Boolean) chooseHasWhen.pop();
+		if (!b.booleanValue())
+		    fail(Resources.getMessage("TLV_PARENT_WITHOUT_SUBTAG",
+			CHOOSE, WHEN));
+		chooseDepths.pop();
+		chooseHasOtherwise.pop();
+	    }
+
+	    // update state related to URL tags
+	    if (isCoreTag(ns, ln, IMPORT)
+                    || isCoreTag(ns, ln, PARAM)
+		    || isCoreTag(ns, ln, REDIRECT)
+		    || isCoreTag(ns, ln, URL))
+		urlTags.pop();
+
+	    // update our depth
+	    depth--;
+	}
+
+	// are we directly under a <choose>?
+	private boolean chooseChild() {
+	    return (!chooseDepths.empty()
+		&& (depth - 1) == ((Integer) chooseDepths.peek()).intValue());
+	}
+
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tlv/JstlFmtTLV.java b/standard/src/org/apache/taglibs/standard/tlv/JstlFmtTLV.java
new file mode 100644
index 0000000..2977940
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tlv/JstlFmtTLV.java
@@ -0,0 +1,255 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tlv;
+
+import java.util.Set;
+import java.util.Stack;
+
+import javax.servlet.jsp.tagext.PageData;
+import javax.servlet.jsp.tagext.ValidationMessage;
+
+import org.apache.taglibs.standard.resources.Resources;
+import org.xml.sax.Attributes;
+import org.xml.sax.helpers.DefaultHandler;
+
+/**
+ * <p>A SAX-based TagLibraryValidator for the JSTL i18n-capable formatting
+ * library. Currently implements the following checks:</p>
+ * 
+ * <ul>
+ *   <li>Expression syntax validation.
+ *   <li>Tag bodies that must either be empty or non-empty given
+ *      particular attributes.</li>
+ * </ul>
+ * 
+ * @author Shawn Bayern
+ * @author Jan Luehe
+ */
+public class JstlFmtTLV extends JstlBaseTLV {
+
+    //*********************************************************************
+    // Implementation Overview
+
+    /*
+     * We essentially just run the page through a SAX parser, handling
+     * the callbacks that interest us.  We collapse <jsp:text> elements
+     * into the text they contain, since this simplifies processing
+     * somewhat.  Even a quick glance at the implementation shows its
+     * necessary, tree-oriented nature:  multiple Stacks, an understanding
+     * of 'depth', and so on all are important as we recover necessary
+     * state upon each callback.  This TLV demonstrates various techniques,
+     * from the general "how do I use a SAX parser for a TLV?" to
+     * "how do I read my init parameters and then validate?"  But also,
+     * the specific SAX methodology was kept as general as possible to
+     * allow for experimentation and flexibility.
+     *
+     * Much of the code and structure is duplicated from JstlCoreTLV.
+     * An effort has been made to re-use code where unambiguously useful.
+     * However, splitting logic among parent/child classes isn't
+     * necessarily the cleanest approach when writing a parser like the
+     * one we need.  I'd like to reorganize this somewhat, but it's not
+     * a priority.
+     */
+
+
+    //*********************************************************************
+    // Constants
+
+    // tag names
+    private final String SETLOCALE = "setLocale";
+    private final String SETBUNDLE = "setBundle";
+    private final String SETTIMEZONE = "setTimeZone";
+    private final String BUNDLE = "bundle";
+    private final String MESSAGE = "message";
+    private final String MESSAGE_PARAM = "param";
+    private final String FORMAT_NUMBER = "formatNumber";
+    private final String PARSE_NUMBER = "parseNumber";
+    private final String PARSE_DATE = "parseDate";
+    // private final String EXPLANG = "expressionLanguage";
+    private final String JSP_TEXT = "jsp:text";
+
+    // attribute names
+    private final String EVAL = "evaluator";
+    private final String MESSAGE_KEY = "key";
+    private final String BUNDLE_PREFIX = "prefix";
+    private final String VALUE = "value";
+
+
+    //*********************************************************************
+    // set its type and delegate validation to super-class
+    public  ValidationMessage[] validate(
+	    String prefix, String uri, PageData page) {
+	return super.validate( TYPE_FMT, prefix, uri, page );
+    }
+
+
+    //*********************************************************************
+    // Contract fulfillment
+
+    protected DefaultHandler getHandler() {
+	return new Handler();
+    }
+
+
+    //*********************************************************************
+    // SAX event handler
+
+    /** The handler that provides the base of our implementation. */
+    private class Handler extends DefaultHandler {
+
+	// parser state
+	private int depth = 0;
+	private Stack messageDepths = new Stack();
+	private String lastElementName = null;
+	private boolean bodyNecessary = false;
+	private boolean bodyIllegal = false;
+
+	// process under the existing context (state), then modify it
+	public void startElement(
+	        String ns, String ln, String qn, Attributes a) {
+
+            // substitute our own parsed 'ln' if it's not provided
+            if (ln == null)
+                ln = getLocalPart(qn);
+
+	    // for simplicity, we can ignore <jsp:text> for our purposes
+	    // (don't bother distinguishing between it and its characters)
+	    if (qn.equals(JSP_TEXT))
+		return;
+
+	    // check body-related constraint
+	    if (bodyIllegal)
+		fail(Resources.getMessage("TLV_ILLEGAL_BODY",
+					  lastElementName));
+
+            // validate expression syntax if we need to
+            Set expAtts;
+            if (qn.startsWith(prefix + ":")
+                    && (expAtts = (Set) config.get(ln)) != null) {
+                for (int i = 0; i < a.getLength(); i++) {
+                    String attName = a.getLocalName(i);
+                    if (expAtts.contains(attName)) {
+                        String vMsg =
+                            validateExpression(
+                                ln,
+                                attName,
+                                a.getValue(i));
+                        if (vMsg != null)
+                            fail(vMsg);
+                    }
+                }
+            }
+
+            // validate attributes
+            if (qn.startsWith(prefix + ":") && !hasNoInvalidScope(a))
+                fail(Resources.getMessage("TLV_INVALID_ATTRIBUTE",
+                    SCOPE, qn, a.getValue(SCOPE)));
+	    if (qn.startsWith(prefix + ":") && hasEmptyVar(a))
+		fail(Resources.getMessage("TLV_EMPTY_VAR", qn));
+            if (qn.startsWith(prefix + ":")
+                && !isFmtTag(ns, ln, SETLOCALE) 
+		&& !isFmtTag(ns, ln, SETBUNDLE)
+		&& !isFmtTag(ns, ln, SETTIMEZONE)
+                && hasDanglingScope(a))
+                fail(Resources.getMessage("TLV_DANGLING_SCOPE", qn));
+
+	    /*
+	     * Make sure <fmt:param> is nested inside <fmt:message>. Note that
+	     * <fmt:param> does not need to be a direct child of <fmt:message>.
+	     * Otherwise, the following would not work:
+	     *
+	     *  <fmt:message key="..." bundle="...">
+	     *   <c:forEach var="arg" items="...">
+	     *    <fmt:param value="${arg}"/>
+	     *   </c:forEach>
+	     *  </fmt:message>
+	     */
+	    if (isFmtTag(ns, ln, MESSAGE_PARAM) && messageDepths.empty()) {
+		fail(Resources.getMessage("PARAM_OUTSIDE_MESSAGE"));
+	    }
+
+	    // now, modify state
+
+	    // If we're in a <message>, record relevant state
+	    if (isFmtTag(ns, ln, MESSAGE)) {
+		messageDepths.push(new Integer(depth));
+	    }
+
+	    // set up a check against illegal attribute/body combinations
+	    bodyIllegal = false;
+	    bodyNecessary = false;
+	    if (isFmtTag(ns, ln, MESSAGE_PARAM)
+		    || isFmtTag(ns, ln, FORMAT_NUMBER)
+		    || isFmtTag(ns, ln, PARSE_NUMBER)
+		    || isFmtTag(ns, ln,  PARSE_DATE)) {
+		if (hasAttribute(a, VALUE))
+		    bodyIllegal = true;
+		else
+		    bodyNecessary = true;
+	    } else if (isFmtTag(ns, ln, MESSAGE)
+		    && !hasAttribute(a, MESSAGE_KEY)) {
+		bodyNecessary = true;
+	    } else if (isFmtTag(ns, ln, BUNDLE)
+		    && hasAttribute(a, BUNDLE_PREFIX)) {
+		bodyNecessary = true;
+	    }
+
+	    // record the most recent tag (for error reporting)
+	    lastElementName = qn;
+            lastElementId = a.getValue(JSP, "id");
+
+	    // we're a new element, so increase depth
+	    depth++;
+	}
+
+	public void characters(char[] ch, int start, int length) {
+
+	    bodyNecessary = false;		// body is no longer necessary!
+
+	    // ignore strings that are just whitespace
+	    String s = new String(ch, start, length).trim();
+	    if (s.equals(""))
+		return;
+
+	    // check and update body-related constraints
+	    if (bodyIllegal)
+		fail(Resources.getMessage("TLV_ILLEGAL_BODY",
+					  lastElementName));
+	}
+
+	public void endElement(String ns, String ln, String qn) {
+
+	    // consistently, we ignore JSP_TEXT
+	    if (qn.equals(JSP_TEXT))
+		return;
+
+	    // handle body-related invariant
+	    if (bodyNecessary)
+		fail(Resources.getMessage("TLV_MISSING_BODY",
+		    lastElementName));
+	    bodyIllegal = false;	// reset: we've left the tag
+
+	    // update <message>-related state
+	    if (isFmtTag(ns, ln, MESSAGE)) {
+		messageDepths.pop();
+	    }
+
+	    // update our depth
+	    depth--;
+	}
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tlv/JstlSqlTLV.java b/standard/src/org/apache/taglibs/standard/tlv/JstlSqlTLV.java
new file mode 100644
index 0000000..3608b6c
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tlv/JstlSqlTLV.java
@@ -0,0 +1,230 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tlv;
+
+import java.util.Set;
+import java.util.Stack;
+
+import javax.servlet.jsp.tagext.PageData;
+import javax.servlet.jsp.tagext.ValidationMessage;
+
+import org.apache.taglibs.standard.resources.Resources;
+import org.xml.sax.Attributes;
+import org.xml.sax.helpers.DefaultHandler;
+
+/**
+ * <p>A SAX-based TagLibraryValidator for the JSTL SQL tag library.
+ * 
+ * @author Shawn Bayern
+ */
+public class JstlSqlTLV extends JstlBaseTLV {
+
+    //*********************************************************************
+    // Constants
+
+    // tag names
+    private final String SETDATASOURCE = "setDataSource";
+    private final String QUERY = "query";
+    private final String UPDATE = "update";
+    private final String TRANSACTION = "transaction";
+    private final String PARAM = "param";
+    private final String DATEPARAM = "dateParam";
+
+    private final String JSP_TEXT = "jsp:text";
+
+    // attribute names
+    private final String SQL = "sql";
+    private final String DATASOURCE = "dataSource";
+
+
+    //*********************************************************************
+    // set its type and delegate validation to super-class
+    public  ValidationMessage[] validate(
+	    String prefix, String uri, PageData page) {
+	return super.validate( TYPE_SQL, prefix, uri, page );
+    }
+
+
+    //*********************************************************************
+    // Contract fulfillment
+
+    protected DefaultHandler getHandler() {
+	return new Handler();
+    }
+
+
+    //*********************************************************************
+    // SAX event handler
+
+    /** The handler that provides the base of our implementation. */
+    private class Handler extends DefaultHandler {
+
+	// parser state
+	private int depth = 0;
+        private Stack queryDepths = new Stack();
+        private Stack updateDepths = new Stack();
+        private Stack transactionDepths = new Stack();
+	private String lastElementName = null;
+	private boolean bodyNecessary = false;
+	private boolean bodyIllegal = false;
+
+	// process under the existing context (state), then modify it
+	public void startElement(
+	        String ns, String ln, String qn, Attributes a) {
+
+	    // substitute our own parsed 'ln' if it's not provided
+	    if (ln == null)
+		ln = getLocalPart(qn);
+
+	    // for simplicity, we can ignore <jsp:text> for our purposes
+	    // (don't bother distinguishing between it and its characters)
+	    if (qn.equals(JSP_TEXT))
+		return;
+
+	    // check body-related constraint
+	    if (bodyIllegal)
+		fail(Resources.getMessage("TLV_ILLEGAL_BODY", lastElementName));
+
+	    // validate expression syntax if we need to
+	    Set expAtts;
+	    if (qn.startsWith(prefix + ":")
+		    && (expAtts = (Set) config.get(ln)) != null) {
+		for (int i = 0; i < a.getLength(); i++) {
+		    String attName = a.getLocalName(i);
+		    if (expAtts.contains(attName)) {
+			String vMsg =
+			    validateExpression(
+				ln,
+				attName,
+				a.getValue(i));
+			if (vMsg != null)
+			    fail(vMsg);
+		    }
+		}
+	    }
+
+            // validate attributes
+            if (qn.startsWith(prefix + ":") && !hasNoInvalidScope(a))
+                fail(Resources.getMessage("TLV_INVALID_ATTRIBUTE",
+                    SCOPE, qn, a.getValue(SCOPE))); 
+	    if (qn.startsWith(prefix + ":") && hasEmptyVar(a))
+		fail(Resources.getMessage("TLV_EMPTY_VAR", qn));
+	    if (qn.startsWith(prefix + ":") && hasDanglingScope(a) &&
+                !qn.startsWith(prefix + ":" + SETDATASOURCE))
+		fail(Resources.getMessage("TLV_DANGLING_SCOPE", qn));
+
+	    // now, modify state
+
+            /*
+             * Make sure <sql:param> is nested inside <sql:query> or
+             * <sql:update>. Note that <sql:param> does not need to
+             * be a direct child of <sql:query> or <sql:update>.
+             * Otherwise, the following would not work:
+             *
+             *  <sql:query sql="..." var="...">
+             *   <c:forEach var="arg" items="...">
+             *    <sql:param value="${arg}"/>
+             *   </c:forEach>
+             *  </sql:query>
+             */
+            if ( (isSqlTag(ns, ln, PARAM) || isSqlTag(ns, ln, DATEPARAM)) 
+                && (queryDepths.empty() && updateDepths.empty()) ) {
+                fail(Resources.getMessage("SQL_PARAM_OUTSIDE_PARENT"));
+            }
+
+            // If we're in a <query>, record relevant state
+            if (isSqlTag(ns, ln, QUERY)) {
+                queryDepths.push(new Integer(depth));
+            }
+            // If we're in a <update>, record relevant state
+            if (isSqlTag(ns, ln, UPDATE)) {
+                updateDepths.push(new Integer(depth));
+            }
+            // If we're in a <transaction>, record relevant state
+            if (isSqlTag(ns, ln, TRANSACTION)) {
+                transactionDepths.push(new Integer(depth));
+            }
+
+	    // set up a check against illegal attribute/body combinations
+	    bodyIllegal = false;
+	    bodyNecessary = false;
+
+            if (isSqlTag(ns, ln, QUERY) || isSqlTag(ns, ln, UPDATE)) {
+                if (!hasAttribute(a, SQL)) {
+                    bodyNecessary = true;
+                }
+                if (hasAttribute(a, DATASOURCE) && !transactionDepths.empty()) {
+                    fail(Resources.getMessage("ERROR_NESTED_DATASOURCE"));
+                }
+            }
+
+            if (isSqlTag(ns, ln, DATEPARAM)) {
+                bodyIllegal = true;
+            }
+
+	    // record the most recent tag (for error reporting)
+	    lastElementName = qn;
+	    lastElementId = a.getValue("http://java.sun.com/JSP/Page", "id");
+
+	    // we're a new element, so increase depth
+	    depth++;
+	}
+
+	public void characters(char[] ch, int start, int length) {
+
+	    bodyNecessary = false;		// body is no longer necessary!
+
+	    // ignore strings that are just whitespace
+	    String s = new String(ch, start, length).trim();
+	    if (s.equals(""))
+		return;
+
+	    // check and update body-related constraints
+	    if (bodyIllegal)
+		fail(Resources.getMessage("TLV_ILLEGAL_BODY", lastElementName));
+	}
+
+	public void endElement(String ns, String ln, String qn) {
+
+	    // consistently, we ignore JSP_TEXT
+	    if (qn.equals(JSP_TEXT))
+		return;
+
+	    // handle body-related invariant
+	    if (bodyNecessary)
+		fail(Resources.getMessage("TLV_MISSING_BODY",
+		    lastElementName));
+	    bodyIllegal = false;	// reset: we've left the tag
+
+            // update <query>-related state
+            if (isSqlTag(ns, ln, QUERY)) {
+                queryDepths.pop();
+            }
+            // update <update>-related state
+            if (isSqlTag(ns, ln, UPDATE)) {
+                updateDepths.pop();
+            }
+            // update <update>-related state
+            if (isSqlTag(ns, ln, TRANSACTION)) {
+                transactionDepths.pop();
+            }
+
+	    // update our depth
+	    depth--;
+	}
+    }
+}
diff --git a/standard/src/org/apache/taglibs/standard/tlv/JstlXmlTLV.java b/standard/src/org/apache/taglibs/standard/tlv/JstlXmlTLV.java
new file mode 100644
index 0000000..c93203c
--- /dev/null
+++ b/standard/src/org/apache/taglibs/standard/tlv/JstlXmlTLV.java
@@ -0,0 +1,306 @@
+/*
+ * Copyright 1999-2004 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.taglibs.standard.tlv;
+
+import java.util.Set;
+import java.util.Stack;
+
+import javax.servlet.jsp.tagext.PageData;
+import javax.servlet.jsp.tagext.ValidationMessage;
+
+import org.apache.taglibs.standard.resources.Resources;
+import org.xml.sax.Attributes;
+import org.xml.sax.helpers.DefaultHandler;
+
+/**
+ * <p>A SAX-based TagLibraryValidator for the JSTL XML library.
+ * Currently implements the following checks:</p>
+ * 
+ * <ul>
+ *   <li>Expression syntax validation.
+ *   <li>Choose / when / otherwise constraints</li>
+ *   <li>Tag bodies that must either be empty or non-empty given
+ *      particular attributes.</li>
+ *   <li>Other minor constraints.</li>
+ * </ul>
+ * 
+ * @author Shawn Bayern
+ */
+public class JstlXmlTLV extends JstlBaseTLV {
+
+    //*********************************************************************
+    // Implementation Overview
+
+    /*
+     * We essentially just run the page through a SAX parser, handling
+     * the callbacks that interest us.  We collapse <jsp:text> elements
+     * into the text they contain, since this simplifies processing
+     * somewhat.  Even a quick glance at the implementation shows its
+     * necessary, tree-oriented nature:  multiple Stacks, an understanding
+     * of 'depth', and so on all are important as we recover necessary
+     * state upon each callback.  This TLV demonstrates various techniques,
+     * from the general "how do I use a SAX parser for a TLV?" to
+     * "how do I read my init parameters and then validate?"  But also,
+     * the specific SAX methodology was kept as general as possible to
+     * allow for experimentation and flexibility.
+     *
+     * Much of the code and structure is duplicated from JstlCoreTLV.
+     * An effort has been made to re-use code where unambiguously useful.
+     * However, splitting logic among parent/child classes isn't
+     * necessarily the cleanest approach when writing a parser like the
+     * one we need.  I'd like to reorganize this somewhat, but it's not
+     * a priority.
+     */
+
+
+    //*********************************************************************
+    // Constants
+
+    // tag names
+    private final String CHOOSE = "choose";
+    private final String WHEN = "when";
+    private final String OTHERWISE = "otherwise";
+    private final String PARSE = "parse";
+    private final String PARAM = "param";
+    private final String TRANSFORM = "transform";
+    private final String JSP_TEXT = "jsp:text";
+
+    // attribute names
+    private final String VALUE = "value";
+    private final String SOURCE = "xml";
+
+
+    //*********************************************************************
+    // set its type and delegate validation to super-class
+    public  ValidationMessage[] validate(
+	    String prefix, String uri, PageData page) {
+	return super.validate( TYPE_XML, prefix, uri, page );
+    }
+
+
+    //*********************************************************************
+    // Contract fulfillment
+
+    protected DefaultHandler getHandler() {
+	return new Handler();
+    }
+
+
+    //*********************************************************************
+    // SAX event handler
+
+    /** The handler that provides the base of our implementation. */
+    private class Handler extends DefaultHandler {
+
+	// parser state
+	private int depth = 0;
+	private Stack chooseDepths = new Stack();
+	private Stack chooseHasOtherwise = new Stack();
+        private Stack chooseHasWhen = new Stack();
+	private String lastElementName = null;
+	private boolean bodyNecessary = false;
+	private boolean bodyIllegal = false;
+	private Stack transformWithSource = new Stack();
+
+	// process under the existing context (state), then modify it
+	public void startElement(
+	        String ns, String ln, String qn, Attributes a) {
+
+            // substitute our own parsed 'ln' if it's not provided
+            if (ln == null)
+                ln = getLocalPart(qn);
+
+	    // for simplicity, we can ignore <jsp:text> for our purposes
+	    // (don't bother distinguishing between it and its characters)
+	    if (qn.equals(JSP_TEXT))
+		return;
+
+	    // check body-related constraint
+	    if (bodyIllegal)
+		fail(Resources.getMessage("TLV_ILLEGAL_BODY", lastElementName));
+
+            // validate expression syntax if we need to
+            Set expAtts;
+            if (qn.startsWith(prefix + ":")
+                    && (expAtts = (Set) config.get(ln)) != null) {
+                for (int i = 0; i < a.getLength(); i++) {
+                    String attName = a.getLocalName(i);
+                    if (expAtts.contains(attName)) {
+                        String vMsg =
+                            validateExpression(
+                                ln,
+                                attName,
+                                a.getValue(i));
+                        if (vMsg != null)
+                            fail(vMsg);
+                    }
+                }
+            }
+
+            // validate attributes
+            if (qn.startsWith(prefix + ":") && !hasNoInvalidScope(a))
+                fail(Resources.getMessage("TLV_INVALID_ATTRIBUTE",
+                    SCOPE, qn, a.getValue(SCOPE)));
+	    if (qn.startsWith(prefix + ":") && hasEmptyVar(a))
+		fail(Resources.getMessage("TLV_EMPTY_VAR", qn));
+            if (qn.startsWith(prefix + ":") && hasDanglingScope(a))
+                fail(Resources.getMessage("TLV_DANGLING_SCOPE", qn));
+
+	    // check invariants for <choose>
+	    if (chooseChild()) {
+                // mark <choose> for the first the first <when>
+                if (isXmlTag(ns, ln, WHEN)) {
+                    chooseHasWhen.pop();
+                    chooseHasWhen.push(Boolean.TRUE);
+                }
+
+		// ensure <choose> has the right children
+		if(!isXmlTag(ns, ln, WHEN) && !isXmlTag(ns, ln, OTHERWISE)) {
+		    fail(Resources.getMessage("TLV_ILLEGAL_CHILD_TAG",
+			prefix, CHOOSE, qn));
+		}
+
+		// make sure <otherwise> is the last tag
+		if (((Boolean) chooseHasOtherwise.peek()).booleanValue()) {
+		   fail(Resources.getMessage("TLV_ILLEGAL_ORDER",
+			qn, prefix, OTHERWISE, CHOOSE));
+		}
+		if (isXmlTag(ns, ln, OTHERWISE)) {
+		    chooseHasOtherwise.pop();
+		    chooseHasOtherwise.push(Boolean.TRUE);
+		}
+
+	    }
+
+	    // Specific check, directly inside <transform source="...">
+	    if (!transformWithSource.empty() &&
+		    topDepth(transformWithSource) == (depth - 1)) {
+		// only allow <param>
+		if (!isXmlTag(ns, ln, PARAM))
+		    fail(Resources.getMessage("TLV_ILLEGAL_BODY",
+			prefix + ":" + TRANSFORM));
+
+		// thus, if we get the opportunity to hit depth++,
+		// we know we've got a <param> subtag
+	    }
+
+	    // now, modify state
+
+	    // we're a choose, so record new choose-specific state
+	    if (isXmlTag(ns, ln, CHOOSE)) {
+		chooseDepths.push(new Integer(depth));
+                chooseHasWhen.push(Boolean.FALSE);
+		chooseHasOtherwise.push(Boolean.FALSE);
+	    }
+
+	    // set up a check against illegal attribute/body combinations
+	    bodyIllegal = false;
+	    bodyNecessary = false;
+	    if (isXmlTag(ns, ln, PARSE)) {
+		if (hasAttribute(a, SOURCE))
+		    bodyIllegal = true;
+	    } else if (isXmlTag(ns, ln, PARAM)) {
+		if (hasAttribute(a, VALUE))
+		    bodyIllegal = true;
+		else
+		    bodyNecessary = true;
+	    } else if (isXmlTag(ns, ln, TRANSFORM)) {
+		if (hasAttribute(a, SOURCE))
+		    transformWithSource.push(new Integer(depth));
+	    }
+
+	    // record the most recent tag (for error reporting)
+	    lastElementName = qn;
+            lastElementId = a.getValue("http://java.sun.com/JSP/Page", "id");
+
+	    // we're a new element, so increase depth
+	    depth++;
+	}
+
+	public void characters(char[] ch, int start, int length) {
+
+	    bodyNecessary = false;		// body is no longer necessary!
+
+	    // ignore strings that are just whitespace
+	    String s = new String(ch, start, length).trim();
+	    if (s.equals(""))
+		return;
+
+	    // check and update body-related constraints
+	    if (bodyIllegal)
+		fail(Resources.getMessage("TLV_ILLEGAL_BODY", lastElementName));
+
+	    // make sure <choose> has no non-whitespace text
+	    if (chooseChild()) {
+		String msg = 
+		    Resources.getMessage("TLV_ILLEGAL_TEXT_BODY",
+			prefix, CHOOSE,
+			(s.length() < 7 ? s : s.substring(0,7)));
+		fail(msg);
+	    }
+
+            // Specific check, directly inside <transform source="...">
+            if (!transformWithSource.empty()
+		    && topDepth(transformWithSource) == (depth - 1)) {
+                fail(Resources.getMessage("TLV_ILLEGAL_BODY",
+                    prefix + ":" + TRANSFORM));
+            }
+	}
+
+	public void endElement(String ns, String ln, String qn) {
+
+	    // consistently, we ignore JSP_TEXT
+	    if (qn.equals(JSP_TEXT))
+		return;
+
+	    // handle body-related invariant
+	    if (bodyNecessary)
+		fail(Resources.getMessage("TLV_MISSING_BODY",
+		    lastElementName));
+	    bodyIllegal = false;	// reset: we've left the tag
+
+	    // update <choose>-related state
+	    if (isXmlTag(ns, ln, CHOOSE)) {
+                Boolean b = (Boolean) chooseHasWhen.pop();
+                if (!b.booleanValue())
+                    fail(Resources.getMessage("TLV_PARENT_WITHOUT_SUBTAG",
+                        CHOOSE, WHEN));
+		chooseDepths.pop();
+		chooseHasOtherwise.pop();
+	    }
+
+	    // update <transform source="...">-related state
+	    if (!transformWithSource.empty()
+		    && topDepth(transformWithSource) == (depth - 1))
+		transformWithSource.pop();
+
+	    // update our depth
+	    depth--;
+	}
+
+	// are we directly under a <choose>?
+	private boolean chooseChild() {
+	    return (!chooseDepths.empty()
+		&& (depth - 1) == ((Integer) chooseDepths.peek()).intValue());
+	}
+
+        // returns the top int depth (peeked at) from a Stack of Integer
+        private int topDepth(Stack s) {
+            return ((Integer) s.peek()).intValue();
+        }
+    }
+}
diff --git a/standard/test/conf/cactus.properties b/standard/test/conf/cactus.properties
new file mode 100644
index 0000000..78328ad
--- /dev/null
+++ b/standard/test/conf/cactus.properties
@@ -0,0 +1,6 @@
+# cactus.contextURL is set in the build-tests.xml
+cactus.contextURL = @cactus.contextURL@
+cactus.enableLogging = false
+cactus.filterRedirectorName = FilterRedirector
+cactus.jspRedirectorName = JspRedirector
+cactus.servletRedirectorName = ServletRedirector
diff --git a/standard/test/org/apache/taglibs/standard/TestVersion.java b/standard/test/org/apache/taglibs/standard/TestVersion.java
new file mode 100644
index 0000000..2a87435
--- /dev/null
+++ b/standard/test/org/apache/taglibs/standard/TestVersion.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 1999,2004 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.taglibs.standard;
+
+import junit.framework.*;
+
+public class TestVersion
+    extends TestCase {
+    private Version version = null;
+
+    public TestVersion(String name) {
+        super(name);
+    }
+
+    protected void setUp() throws Exception {
+        super.setUp();
+        version = new Version();
+    }
+
+    protected void tearDown() throws Exception {
+        version = null;
+        super.tearDown();
+    }
+
+    public void testVersion() {
+        version = new Version();
+    }
+
+    public void testGetDevelopmentVersionNum() {
+        int expectedReturn = 0;
+        int actualReturn = version.getDevelopmentVersionNum();
+        assertEquals("return value", expectedReturn, actualReturn);
+    }
+
+    public void testGetMaintenanceVersionNum() {
+        int expectedReturn = 0;
+        int actualReturn = version.getMaintenanceVersionNum();
+        assertEquals("return value", expectedReturn, actualReturn);
+    }
+
+    public void testGetMajorVersionNum() {
+        int expectedReturn = 1;
+        int actualReturn = version.getMajorVersionNum();
+        assertEquals("return value", expectedReturn, actualReturn);
+    }
+
+    public void testGetProduct() {
+        String expectedReturn = "standard-taglib";
+        String actualReturn = version.getProduct();
+        assertEquals("return value", expectedReturn, actualReturn);
+    }
+
+    public void testGetReleaseVersionNum() {
+        int expectedReturn = 1;
+        int actualReturn = version.getReleaseVersionNum();
+        assertEquals("return value", expectedReturn, actualReturn);
+    }
+
+    public void testGetVersion() {
+        String expectedReturn = "standard-taglib 1.1.0";
+        String actualReturn = version.getVersion();
+        assertEquals("return value", expectedReturn, actualReturn);
+    }
+
+    public void testMain() {
+        String[] argv = null;
+        version.main(argv);
+    }
+
+}
diff --git a/standard/test/org/apache/taglibs/standard/tag/el/core/TestSetTag.java b/standard/test/org/apache/taglibs/standard/tag/el/core/TestSetTag.java
new file mode 100644
index 0000000..8b35231
--- /dev/null
+++ b/standard/test/org/apache/taglibs/standard/tag/el/core/TestSetTag.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 1999,2004 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.taglibs.standard.tag.el.core;
+
+import javax.servlet.jsp.*;
+import org.apache.cactus.*;
+import org.apache.taglibs.standard.testutil.TestUtil;
+
+public class TestSetTag
+    extends JspTestCase {
+//    private SetTag setTag = null;
+
+    public TestSetTag(String name) {
+        super(name);
+    }
+
+    protected void setUp() throws Exception {
+        super.setUp();
+    }
+
+    protected void tearDown() throws Exception {
+        super.tearDown();
+    }
+
+    public void testSetTag() throws Exception {
+        String var = "var1";
+        String expected = "value1";
+        String toInclude = TestUtil.getTestJsp(this);
+        pageContext.include(toInclude);
+        String actual = (String) pageContext.getAttribute(var,
+            PageContext.APPLICATION_SCOPE);
+        assertEquals(expected, actual);
+    }
+}
diff --git a/standard/test/org/apache/taglibs/standard/testutil/TestUtil.java b/standard/test/org/apache/taglibs/standard/testutil/TestUtil.java
new file mode 100644
index 0000000..b625f19
--- /dev/null
+++ b/standard/test/org/apache/taglibs/standard/testutil/TestUtil.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 1999,2004 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.taglibs.standard.testutil;
+
+public class TestUtil {
+    
+    private TestUtil() {}
+
+    /**
+     * Gets the corresponding test jsp for this test case.  As a convention,
+     * test class and test jsp should have the same package and directory
+     * structure, and the same base name.
+     * @return a context-relative path to the test jsp.
+     */
+     public static String getTestJsp(Object obj) {
+         String className = obj.getClass().getName();
+         String baseName = className.replace('.', '/');
+         return "/" + baseName + ".jsp";
+     }
+}
diff --git a/standard/test/web/WEB-INF/web.xml b/standard/test/web/WEB-INF/web.xml
new file mode 100644
index 0000000..3922ced
--- /dev/null
+++ b/standard/test/web/WEB-INF/web.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app version="2.4"
+         xmlns="http://java.sun.com/xml/ns/j2ee"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
+    <description>jstl test</description>
+    <display-name>jstl test</display-name>
+<!--
+    <filter>
+        <filter-name>FilterRedirectory</filter-name>
+        <filter-class>
+            org.apache.cactus.server.FilterTestRedirector
+        </filter-class>
+    </filter>
+
+    <filter-mapping>
+        <filter-name>FilterRedirector</filter-name>
+        <url-pattern>/FilterRedirector</url-pattern>
+    </filter-mapping>
+-->
+
+    <servlet>
+        <servlet-name>ServletRedirector</servlet-name>
+        <servlet-class>
+            org.apache.cactus.server.ServletTestRedirector
+        </servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>JspRedirector</servlet-name>
+        <jsp-file>/jspRedirector.jsp</jsp-file>
+    </servlet>
+    
+    <servlet-mapping>
+        <servlet-name>ServletRedirector</servlet-name>
+        <url-pattern>/ServletRedirector</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>JspRedirector</servlet-name>
+        <url-pattern>/JspRedirector</url-pattern>
+    </servlet-mapping>
+    
+</web-app>
diff --git a/standard/test/web/org/apache/taglibs/standard/tag/el/core/TestSetTag.jsp b/standard/test/web/org/apache/taglibs/standard/tag/el/core/TestSetTag.jsp
new file mode 100644
index 0000000..3199999
--- /dev/null
+++ b/standard/test/web/org/apache/taglibs/standard/tag/el/core/TestSetTag.jsp
@@ -0,0 +1,4 @@
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+
+<c:set var="var1" value="value1" scope="application"/>
+<c:out value="${var1}"/>
diff --git a/standard/xml/intro.xml b/standard/xml/intro.xml
new file mode 100644
index 0000000..0363811
--- /dev/null
+++ b/standard/xml/intro.xml
@@ -0,0 +1,172 @@
+<?xml version="1.0"?>
+<document url="./intro.xml">
+
+<properties>
+  <author>Shawn Bayern</author>
+  <title>The Jakarta-Taglibs Project: Standard-1.1 taglib: JSP[tm] Standard Tag Library (JSTL 1.1) implementation</title>
+</properties>
+
+<body>
+
+  <section name="Standard-1.1 Taglib" href="Welcome">
+
+    <big><b>JSP(tm) Standard Tag Library 1.1 implementation</b></big>
+
+    <p>Jakarta Taglibs hosts the Standard Taglib 1.1, an implementation of
+      the <a href="http://java.sun.com/products/jsp/jstl">JSP Standard Tag
+      Library (JSTL)</a>, version 1.1, which was developed under the
+      <a href="http://jcp.org/">Java Community Process</a>.
+    </p>
+
+    <p><b>NOTE:</b> Standard-1.1 (JSTL 1.1) requires a JSP container that supports
+      the Java Servlet 2.4 and JavaServer Pages 2.0 specifications.
+      Jakarta <a href="http://jakarta.apache.org/tomcat/">
+      Tomcat 5</a> supports the new specifications. The Standard-1.1 taglib
+      has been tested with Tomcat 5.0.3.</p>
+    <p><a href="http://jakarta.apache.org/taglibs/doc/standard-1.0-doc/intro.html">Standard-1.0</a>
+    (implementation of the JSTL 1.0 specification) requires a JSP container that supports
+      the Java Servlet 2.3 and JavaServer Pages 1.2 specifications.
+      Jakarta <a href="http://jakarta.apache.org/tomcat/">
+      Tomcat 4</a> supports these specifications. The Standard 1.0 taglib
+      has been tested with Tomcat 4.1.24.
+    </p>
+
+  </section>
+
+  <section name="Standard-1.1 Taglib News" href="News">
+
+    <news>
+      <newsitem date="10/25/2004">
+       Standard Taglib version 1.1.2 
+       - A minor bug fix update - 
+       is now available from the 
+       <a href="http://jakarta.apache.org/site/binindex.cgi#Release%20Builds">
+       Apache Jakarta Project Mirrors</a>.
+      </newsitem>
+      <newsitem date="07/20/2004">
+       Standard Taglib version 1.1.1 
+       - A minor bug fix update - 
+       is now available from the 
+       <a href="http://jakarta.apache.org/site/binindex.cgi#Release%20Builds">
+       Apache Jakarta Project Mirrors</a>.
+      </newsitem>
+      <newsitem date="01/30/2004">
+       Standard Taglib version 1.1.0 - First official release of our 
+       implementation of JSTL 1.1 - is now
+       available from the <a href="http://jakarta.apache.org/site/binindex.cgi#Release%20Builds">
+       Apache Jakarta Project Mirrors</a>.
+      </newsitem>
+      <newsitem date="09/25/2003">
+       Standard Taglib version 1.1.0-B1 - early access (Beta 1) of our 
+       implementation of JSTL 1.1 - is now
+       available from the <a href="http://jakarta.apache.org/site/binindex.cgi#Release%20Builds">
+       Apache Jakarta Project Mirrors</a>.
+      </newsitem>
+    </news>
+
+  </section>
+
+  <section name="Documentation" href="Documentation">
+
+    <p>For more information about the Standard Taglib,
+       look at the on-line documentation:</p>
+    <ul>
+      <!--  Uncomment this section and modify as needed when you start
+            doing releases of the taglib, a link can be made to each
+            available release. -->
+      <li>View the Standard 1.1 taglib documentation
+        <a href="standard/index.html">Standard 1.1 Documentation</a>
+      </li>
+
+      <li>View the most recent, nightly build of the
+        <a href="index.html">Standard Taglib Documentation</a>
+      </li>
+    </ul>
+  
+    <p>For information on how to use the distributions,
+       look at the following documentation:</p>
+  
+    <ul>
+	<li><a href="http://jakarta.apache.org/taglibs/binarydist.html">
+	Using the Jakarta-Taglibs
+        Binary Distribution</a></li>
+      <li>
+        <a href="http://jakarta.apache.org/taglibs/sourcedist.html">
+        Using the Jakarta-Taglibs
+        Source Distribution</a></li>
+    </ul>
+
+    <p>Several books have been written about JSTL.  See the <a
+    href="#Books">JSTL Books</a> section below for more documentation.</p>
+  
+  </section>
+
+  <section name="Download" href="Download">
+
+    <!--  Uncomment this section and modify as needed when you start
+          doing releases of the taglib. -->
+    <p>Download a binary distribution of the Standard release:</p>
+    <ul>
+      <li>
+        Download the Standard Tag Library Release from an
+        <a href="http://jakarta.apache.org/site/binindex.cgi#Release%20Builds">
+        Apache Jakarta Project Mirror</a>
+      </li>
+    </ul>
+
+    <p>Download the most recent, nightly snapshot:</p>
+    <ul>
+      <li>
+        <a href="http://jakarta.apache.org/builds/jakarta-taglibs/nightly/projects/standard/">
+        Standard Taglib nightly snapshot</a></li>
+    </ul>
+
+    <p>Nightly build distributions of the development version for all the
+      Jakarta-Taglibs are available for download:</p>
+    <ul>
+      <li>Download
+        <a href="http://jakarta.apache.org/builds/jakarta-taglibs/nightly/src/">
+        Jakarta-Taglibs Source</a></li>
+      <li>Download entire
+        <a href="http://jakarta.apache.org/builds/jakarta-taglibs/nightly">
+        Jakarta-Taglibs Distribution</a></li>
+    </ul>
+
+  </section>
+
+  <section name="JSTL Books" href="Books">
+
+    <p>The following books about JSTL are available:</p>
+
+    <ul>
+      <li><a href="http://jstlbook.com/"><i>JSTL in Action</i></a>, Shawn Bayern, Manning</li>
+      <li><a href="http://TheJSPBook.com/"><i>JavaServer Pages</i></a>, Hans Bergsten, O'Reilly</li>
+      <li><a href="http://www.core-jstl.com"><i>Core JSTL: Mastering the JSP Standard Tag Library</i></a>, David Geary, Sun Microsystems Press</li>
+    </ul>
+
+  </section>
+
+  <section name="Contributors" href="Contributors">
+
+    <p>List of contributors:</p>
+
+    <ul>
+      <li>The <a href="http://www.jcp.org/jsr/detail/52.jsp">JSR-052 Expert Group</a></li>
+      <li>Pierre Delisle (specification lead)</li>
+      <li>Shawn Bayern (implementation lead)</li>
+      <li>Nathan Abramson</li>
+      <li>Hans Bergsten</li>
+      <li>Scott Hasse</li>
+      <li>Justyna Horwat</li>
+      <li>Mark Kolb</li>
+      <li>Jan Luehe</li>
+      <li>Glenn Nielsen</li>
+      <li>Dmitri Plotnikov</li>
+      <li>Felipe Leme</li>
+    </ul>
+
+  </section>
+
+  </body>
+
+</document>

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-java/jakarta-taglibs-standard.git



More information about the pkg-java-commits mailing list