14c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson/*
24c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson * Licensed to the Apache Software Foundation (ASF) under one
34c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson * or more contributor license agreements. See the NOTICE file
44c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson * distributed with this work for additional information
54c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson * regarding copyright ownership. The ASF licenses this file
64c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson * to you under the Apache License, Version 2.0 (the  "License");
74c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson * you may not use this file except in compliance with the License.
84c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson * You may obtain a copy of the License at
94c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson *
104c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson *     http://www.apache.org/licenses/LICENSE-2.0
114c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson *
124c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson * Unless required by applicable law or agreed to in writing, software
134c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson * distributed under the License is distributed on an "AS IS" BASIS,
144c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
154c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson * See the License for the specific language governing permissions and
164c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson * limitations under the License.
174c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson */
184c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson/*
194c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson * $Id: ElemApplyTemplates.java 468643 2006-10-28 06:56:03Z minchau $
204c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson */
214c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilsonpackage org.apache.xalan.templates;
224c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson
234c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilsonimport java.util.Vector;
244c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson
254c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilsonimport javax.xml.transform.TransformerException;
264c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson
274c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilsonimport org.apache.xalan.transformer.TransformerImpl;
284c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilsonimport org.apache.xml.dtm.DTM;
294c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilsonimport org.apache.xml.dtm.DTMIterator;
304c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilsonimport org.apache.xml.serializer.SerializationHandler;
314c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilsonimport org.apache.xml.utils.IntStack;
324c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilsonimport org.apache.xml.utils.QName;
334c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilsonimport org.apache.xpath.VariableStack;
344c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilsonimport org.apache.xpath.XPath;
354c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilsonimport org.apache.xpath.XPathContext;
364c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilsonimport org.apache.xpath.objects.XObject;
374c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilsonimport org.xml.sax.SAXException;
384c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson
394c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson/**
404c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson * Implement xsl:apply-templates.
414c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson * <pre>
424c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson * &amp;!ELEMENT xsl:apply-templates (xsl:sort|xsl:with-param)*>
434c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson * &amp;!ATTLIST xsl:apply-templates
444c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson *   select %expr; "node()"
454c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson *   mode %qname; #IMPLIED
464c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson * &amp;
474c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson * </pre>
484c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson * @see <a href="http://www.w3.org/TR/xslt#section-Applying-Template-Rules">section-Applying-Template-Rules in XSLT Specification</a>
494c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson * @xsl.usage advanced
504c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson */
514c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilsonpublic class ElemApplyTemplates extends ElemCallTemplate
524c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson{
534c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson    static final long serialVersionUID = 2903125371542621004L;
544c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson
554c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson  /**
564c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson   * mode %qname; #IMPLIED
574c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson   * @serial
584c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson   */
594c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson  private QName m_mode = null;
604c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson
614c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson  /**
624c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson   * Set the mode attribute for this element.
634c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson   *
644c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson   * @param mode reference, which may be null, to the <a href="http://www.w3.org/TR/xslt#modes">current mode</a>.
654c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson   */
664c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson  public void setMode(QName mode)
674c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson  {
684c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson    m_mode = mode;
694c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson  }
704c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson
714c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson  /**
724c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson   * Get the mode attribute for this element.
734c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson   *
744c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson   * @return The mode attribute for this element
754c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson   */
764c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson  public QName getMode()
774c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson  {
784c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson    return m_mode;
794c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson  }
804c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson
814c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson  /**
824c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson   * Tells if this belongs to a default template,
834c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson   * in which case it will act different with
844c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson   * regard to processing modes.
854c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson   * @see <a href="http://www.w3.org/TR/xslt#built-in-rule">built-in-rule in XSLT Specification</a>
864c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson   * @serial
874c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson   */
884c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson  private boolean m_isDefaultTemplate = false;
894c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson
904c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson//  /**
914c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson//   * List of namespace/localname IDs, for identification of xsl:with-param to
924c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson//   * xsl:params.  Initialized in the compose() method.
934c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson//   */
944c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson//  private int[] m_paramIDs;
954c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson
964c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson  /**
974c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson   * Set if this belongs to a default template,
984c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson   * in which case it will act different with
994c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson   * regard to processing modes.
1004c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson   * @see <a href="http://www.w3.org/TR/xslt#built-in-rule">built-in-rule in XSLT Specification</a>
1014c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson   *
1024c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson   * @param b boolean value to set.
1034c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson   */
1044c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson  public void setIsDefaultTemplate(boolean b)
1054c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson  {
1064c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson    m_isDefaultTemplate = b;
1074c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson  }
1084c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson
1094c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson  /**
1104c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson   * Get an int constant identifying the type of element.
1114c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson   * @see org.apache.xalan.templates.Constants
1124c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson   *
1134c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson   * @return Token ID for this element types
1144c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson   */
1154c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson  public int getXSLToken()
1164c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson  {
1174c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson    return Constants.ELEMNAME_APPLY_TEMPLATES;
1184c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson  }
1194c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson
1204c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson  /**
1214c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson   * This function is called after everything else has been
1224c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson   * recomposed, and allows the template to set remaining
1234c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson   * values that may be based on some other property that
1244c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson   * depends on recomposition.
1254c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson   */
1264c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson  public void compose(StylesheetRoot sroot) throws TransformerException
1274c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson  {
1284c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson    super.compose(sroot);
1294c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson  }
1304c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson
1314c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson  /**
1324c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson   * Return the node name.
1334c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson   *
1344c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson   * @return Element name
1354c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson   */
1364c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson  public String getNodeName()
1374c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson  {
1384c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson    return Constants.ELEMNAME_APPLY_TEMPLATES_STRING;
1394c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson  }
1404c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson
1414c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson  /**
1424c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson   * Apply the context node to the matching templates.
1434c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson   * @see <a href="http://www.w3.org/TR/xslt#section-Applying-Template-Rules">section-Applying-Template-Rules in XSLT Specification</a>
1444c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson   *
1454c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson   * @param transformer non-null reference to the the current transform-time state.
1464c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson   *
1474c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson   * @throws TransformerException
1484c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson   */
1494c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson  public void execute(TransformerImpl transformer) throws TransformerException
1504c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson  {
1514c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson
1524c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson    transformer.pushCurrentTemplateRuleIsNull(false);
1534c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson
1544c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson    boolean pushMode = false;
1554c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson
1564c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson    try
1574c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson    {
1584c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson      // %REVIEW% Do we need this check??
1594c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson      //      if (null != sourceNode)
1604c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson      //      {
1614c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson      // boolean needToTurnOffInfiniteLoopCheck = false;
1624c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson      QName mode = transformer.getMode();
1634c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson
1644c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson      if (!m_isDefaultTemplate)
1654c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson      {
1664c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson        if (((null == mode) && (null != m_mode))
1674c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson                || ((null != mode) &&!mode.equals(m_mode)))
1684c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson        {
1694c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson          pushMode = true;
1704c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson
1714c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson          transformer.pushMode(m_mode);
1724c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson        }
1734c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson      }
1744c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson
1754c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson      transformSelectedNodes(transformer);
1764c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson    }
1774c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson    finally
1784c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson    {
1794c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson      if (pushMode)
1804c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson        transformer.popMode();
1814c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson
1824c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson      transformer.popCurrentTemplateRuleIsNull();
1834c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson    }
1844c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson  }
1854c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson
1864c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson
1874c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson  /**
1884c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson   * Perform a query if needed, and call transformNode for each child.
1894c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson   *
1904c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson   * @param transformer non-null reference to the the current transform-time state.
1914c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson   *
1924c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson   * @throws TransformerException Thrown in a variety of circumstances.
1934c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson   * @xsl.usage advanced
1944c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson   */
1954c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson  public void transformSelectedNodes(TransformerImpl transformer)
1964c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson            throws TransformerException
1974c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson  {
1984c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson
1994c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson    final XPathContext xctxt = transformer.getXPathContext();
2004c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson    final int sourceNode = xctxt.getCurrentNode();
2014c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson    DTMIterator sourceNodes = m_selectExpression.asIterator(xctxt, sourceNode);
2024c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson    VariableStack vars = xctxt.getVarStack();
2034c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson    int nParams = getParamElemCount();
2044c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson    int thisframe = vars.getStackFrame();
2050b4ea6cb0176b34c7ac46800d51ce925683ef667Jesse Wilson
2064c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson    boolean pushContextNodeListFlag = false;
2074c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson
2084c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson    try
2094c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson    {
2104c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson
2114c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson            xctxt.pushCurrentNode(DTM.NULL);
2124c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson            xctxt.pushCurrentExpressionNode(DTM.NULL);
2134c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson            xctxt.pushSAXLocatorNull();
2144c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson            transformer.pushElemTemplateElement(null);
2154c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson      final Vector keys = (m_sortElems == null)
2164c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson                          ? null
2174c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson                          : transformer.processSortKeys(this, sourceNode);
2184c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson
2194c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson      // Sort if we need to.
2204c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson      if (null != keys)
2214c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson        sourceNodes = sortNodes(xctxt, keys, sourceNodes);
2224c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson
2234c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson      final SerializationHandler rth = transformer.getSerializationHandler();
2244c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson//      ContentHandler chandler = rth.getContentHandler();
2254c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson      final StylesheetRoot sroot = transformer.getStylesheet();
2264c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson      final TemplateList tl = sroot.getTemplateListComposed();
2274c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson      final boolean quiet = transformer.getQuietConflictWarnings();
2284c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson
2294c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson      // Should be able to get this from the iterator but there must be a bug.
2304c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson      DTM dtm = xctxt.getDTM(sourceNode);
2314c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson
2324c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson      int argsFrame = -1;
2334c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson      if(nParams > 0)
2344c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson      {
2354c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson        // This code will create a section on the stack that is all the
2364c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson        // evaluated arguments.  These will be copied into the real params
2374c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson        // section of each called template.
2384c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson        argsFrame = vars.link(nParams);
2394c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson        vars.setStackFrame(thisframe);
2404c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson
2414c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson        for (int i = 0; i < nParams; i++)
2424c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson        {
2434c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson          ElemWithParam ewp = m_paramElems[i];
2444c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson          XObject obj = ewp.getValue(transformer, sourceNode);
2450b4ea6cb0176b34c7ac46800d51ce925683ef667Jesse Wilson
2464c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson          vars.setLocalVariable(i, obj, argsFrame);
2474c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson        }
2484c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson        vars.setStackFrame(argsFrame);
2494c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson      }
2504c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson
2514c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson      xctxt.pushContextNodeList(sourceNodes);
2524c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson      pushContextNodeListFlag = true;
2534c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson
2544c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson      IntStack currentNodes = xctxt.getCurrentNodeStack();
2554c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson
2564c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson      IntStack currentExpressionNodes = xctxt.getCurrentExpressionNodeStack();
2574c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson
2584c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson      // pushParams(transformer, xctxt);
2594c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson
2604c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson      int child;
2614c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson      while (DTM.NULL != (child = sourceNodes.nextNode()))
2624c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson      {
2634c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson        currentNodes.setTop(child);
2644c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson        currentExpressionNodes.setTop(child);
2654c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson
2664c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson        if(xctxt.getDTM(child) != dtm)
2674c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson        {
2684c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson          dtm = xctxt.getDTM(child);
2694c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson        }
2704c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson
2714c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson        final int exNodeType = dtm.getExpandedTypeID(child);
2724c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson
2734c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson        final int nodeType = dtm.getNodeType(child);
2744c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson
2754c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson        final QName mode = transformer.getMode();
2764c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson
2774c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson        ElemTemplate template = tl.getTemplateFast(xctxt, child, exNodeType, mode,
2784c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson                                      -1, quiet, dtm);
2794c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson
2804c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson        // If that didn't locate a node, fall back to a default template rule.
2814c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson        // See http://www.w3.org/TR/xslt#built-in-rule.
2824c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson        if (null == template)
2834c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson        {
2844c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson          switch (nodeType)
2854c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson          {
2864c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson          case DTM.DOCUMENT_FRAGMENT_NODE :
2874c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson          case DTM.ELEMENT_NODE :
2884c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson            template = sroot.getDefaultRule();
2894c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson            // %OPT% direct faster?
2904c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson            break;
2914c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson          case DTM.ATTRIBUTE_NODE :
2924c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson          case DTM.CDATA_SECTION_NODE :
2934c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson          case DTM.TEXT_NODE :
2944c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson            // if(rth.m_elemIsPending || rth.m_docPending)
2954c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson            //  rth.flushPending(true);
2964c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson            transformer.pushPairCurrentMatched(sroot.getDefaultTextRule(), child);
2974c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson            transformer.setCurrentElement(sroot.getDefaultTextRule());
2984c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson            // dtm.dispatchCharactersEvents(child, chandler, false);
2994c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson            dtm.dispatchCharactersEvents(child, rth, false);
3004c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson            transformer.popCurrentMatched();
3014c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson            continue;
3024c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson          case DTM.DOCUMENT_NODE :
3034c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson            template = sroot.getDefaultRootRule();
3044c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson            break;
3054c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson          default :
3064c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson
3074c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson            // No default rules for processing instructions and the like.
3084c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson            continue;
3094c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson          }
3104c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson        }
3114c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson        else
3124c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson        {
3134c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson        	transformer.setCurrentElement(template);
3144c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson        }
3154c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson
3164c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson        transformer.pushPairCurrentMatched(template, child);
3174c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson
3184c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson        int currentFrameBottom;  // See comment with unlink, below
3194c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson        if(template.m_frameSize > 0)
3204c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson        {
3214c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson          xctxt.pushRTFContext();
3224c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson          currentFrameBottom = vars.getStackFrame();  // See comment with unlink, below
3234c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson          vars.link(template.m_frameSize);
3244c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson          // You can't do the check for nParams here, otherwise the
3254c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson          // xsl:params might not be nulled.
3264c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson          if(/* nParams > 0 && */ template.m_inArgsSize > 0)
3274c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson          {
3284c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson            int paramIndex = 0;
3294c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson            for (ElemTemplateElement elem = template.getFirstChildElem();
3304c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson                 null != elem; elem = elem.getNextSiblingElem())
3314c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson            {
3324c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson              if(Constants.ELEMNAME_PARAMVARIABLE == elem.getXSLToken())
3334c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson              {
3344c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson                ElemParam ep = (ElemParam)elem;
3354c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson
3364c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson                int i;
3374c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson                for (i = 0; i < nParams; i++)
3384c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson                {
3394c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson                  ElemWithParam ewp = m_paramElems[i];
3404c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson                  if(ewp.m_qnameID == ep.m_qnameID)
3414c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson                  {
3424c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson                    XObject obj = vars.getLocalVariable(i, argsFrame);
3434c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson                    vars.setLocalVariable(paramIndex, obj);
3444c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson                    break;
3454c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson                  }
3464c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson                }
3474c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson                if(i == nParams)
3484c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson                  vars.setLocalVariable(paramIndex, null);
3494c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson              }
3504c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson              else
3514c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson                break;
3524c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson              paramIndex++;
3534c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson            }
3544c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson
3554c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson          }
3564c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson        }
3574c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson        else
3584c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson        	currentFrameBottom = 0;
3594c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson
3604c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson        // And execute the child templates.
3614c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson        // Loop through the children of the template, calling execute on
3624c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson        // each of them.
3634c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson        for (ElemTemplateElement t = template.m_firstChild;
3644c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson             t != null; t = t.m_nextSibling)
3654c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson        {
3664c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson          xctxt.setSAXLocator(t);
3674c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson          try
3684c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson          {
3694c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson          	transformer.pushElemTemplateElement(t);
3704c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson          	t.execute(transformer);
3714c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson          }
3724c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson          finally
3734c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson          {
3744c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson          	transformer.popElemTemplateElement();
3754c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson          }
3764c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson        }
3774c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson
3784c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson        if(template.m_frameSize > 0)
3794c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson        {
3804c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson          // See Frank Weiss bug around 03/19/2002 (no Bugzilla report yet).
3814c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson          // While unlink will restore to the proper place, the real position
3824c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson          // may have been changed for xsl:with-param, so that variables
3834c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson          // can be accessed.
3844c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson          // of right now.
3854c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson          // More:
3864c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson          // When we entered this function, the current
3874c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson          // frame buffer (cfb) index in the variable stack may
3884c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson          // have been manually set.  If we just call
3894c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson          // unlink(), however, it will restore the cfb to the
3904c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson          // previous link index from the link stack, rather than
3914c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson          // the manually set cfb.  So,
3924c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson          // the only safe solution is to restore it back
3934c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson          // to the same position it was on entry, since we're
3944c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson          // really not working in a stack context here. (Bug4218)
3954c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson          vars.unlink(currentFrameBottom);
3964c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson          xctxt.popRTFContext();
3974c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson        }
3984c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson
3994c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson        transformer.popCurrentMatched();
4004c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson
4014c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson      } // end while (DTM.NULL != (child = sourceNodes.nextNode()))
4024c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson    }
4034c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson    catch (SAXException se)
4044c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson    {
4054c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson      transformer.getErrorListener().fatalError(new TransformerException(se));
4064c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson    }
4074c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson    finally
4084c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson    {
4090b4ea6cb0176b34c7ac46800d51ce925683ef667Jesse Wilson      // Unlink to the original stack frame
4104c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson      if(nParams > 0)
4114c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson        vars.unlink(thisframe);
4124c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson      xctxt.popSAXLocator();
4134c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson      if (pushContextNodeListFlag) xctxt.popContextNodeList();
4144c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson      transformer.popElemTemplateElement();
4154c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson      xctxt.popCurrentExpressionNode();
4164c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson      xctxt.popCurrentNode();
4174c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson      sourceNodes.detach();
4184c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson    }
4194c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson  }
4204c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson
4214c7a0d97cf2b27790e6236965a1d798d710d7ec7Jesse Wilson}
422