/// <summary>
        /// Recursively evaluates the template nodes returned from the Proccessor
        /// </summary>
        /// <param name="node">the node to evaluate</param>
        /// <param name="query">the query that produced targetBot node</param>
        /// <param name="request">the request from the user</param>
        /// <param name="result">the result to be sent to the user</param>
        /// <param name="user">the user who originated the request</param>
        /// <returns>the output Unifiable</returns>
        public string processNode(XmlNode node, SubQuery query,
                                  Request request, Result result, User user,
                                  AIMLTagHandler parentHandlerU, bool protectChild, bool copyParent,
                                  AIMLTagHandler nodeHandlerU, bool suspendLimits, out bool templateSucceeded)
        {
            Request originalSalientRequest = Request.GetOriginalSalientRequest(request);
            bool    osrExists          = originalSalientRequest != null;
            var     wasSuspendRestrati = request == null || request.SuspendSearchLimits;

            templateSucceeded = true;
            if (request != null)
            {
                request.SuspendSearchLimits = suspendLimits;
            }
            Dictionary <Unifiable, Unifiable> sraiMark = null;

            if (osrExists && ChatOptions.UseSraiLimitersBasedOnTextContent)
            {
                sraiMark = originalSalientRequest.CreateSRAIMark();
            }
            try
            {
                bool   childSuccess;
                string outputSentence = processNodeVV(node, query,
                                                      request, result, user, parentHandlerU,
                                                      protectChild, copyParent, nodeHandlerU, out childSuccess);
                if (!childSuccess)
                {
                    templateSucceeded = false;
                }
                if (Unifiable.IsNull(outputSentence))
                {
                    //outputSentence = tagHandler.GetTemplateNodeInnerText();
                    templateSucceeded = false;
                    return(outputSentence);
                }
                if (!Unifiable.IsNullOrEmpty(outputSentence))
                {
                    return(outputSentence);
                }
                if (StaticAIMLUtils.IsSilentTag(node) && !Unifiable.IsEMPTY(outputSentence))
                {
                    return("");
                }
                if (nodeHandlerU.FinalResultValid)
                {
                    return(nodeHandlerU.FinalResult);
                }
                return(outputSentence);
            }
            finally
            {
                if (osrExists && ChatOptions.UseSraiLimitersBasedOnTextContent)
                {
                    originalSalientRequest.ResetSRAIResults(sraiMark);
                }
                if (request != null)
                {
                    request.SuspendSearchLimits = wasSuspendRestrati;
                }
            }
        }
        /// <summary>
        /// Recursively evaluates the template nodes returned from the Proccessor
        /// </summary>
        /// <param name="node">the node to evaluate</param>
        /// <param name="query">the query that produced targetBot node</param>
        /// <param name="request">the request from the user</param>
        /// <param name="result">the result to be sent to the user</param>
        /// <param name="user">the user who originated the request</param>
        /// <returns>the output Unifiable</returns>
        public string processNodeVV(XmlNode node, SubQuery query,
                                    Request request, Result result, User user,
                                    AIMLTagHandler parentHandlerU, bool protectChild, bool copyParent,
                                    AIMLTagHandler tagHandlerU, out bool childSuccess)
        {
            AltBot TargetBot = tagHandlerU.bot;

            if (request != null)
            {
                TargetBot = request.TargetBot;
            }
            childSuccess = true;
            if (node == null)
            {
                string whyError = "ERROR null NODE " + tagHandlerU;
                writeToLog(whyError);
                throw new ChatSignalOverBudget(request, whyError);
            }
            if (node.NodeType == XmlNodeType.Text)
            {
                childSuccess = true;
                if (tagHandlerU != null)
                {
                    tagHandlerU.QueryHasSuceeded = true;
                }
                string s = StaticAIMLUtils.Trim(StaticAIMLUtils.TextNodeValue(node));
                if (!String.IsNullOrEmpty(s))
                {
                    return(StaticAIMLUtils.ValueText(s));
                }
                //return s;
            }
            if (tagHandlerU == null)
            {
                string whyError = "ERROR null THND " + node;
                childSuccess = false;
                writeToLog(whyError);
            }
            bool isTraced = (request != null && (request.IsTraced || !request.GraphsAcceptingUserInput)) ||
                            (query != null && query.IsTraced);

            // check for timeout (to avoid infinite loops)
            bool overBudget = false;

            if (request != null && request.IsComplete(result))
            {
                object gn = request.Graph;
                if (query != null)
                {
                    gn = query.Graph;
                }
                string s = StaticAIMLUtils.SafeFormat("WARNING! Request " + request.WhyComplete +
                                                      ". User: {0} raw input: {3} \"{1}\" processing {2} templates: \"{4}\"",
                                                      request.Requester.UserID, Unifiable.DescribeUnifiable(request.rawInput),
                                                      (query == null ? "-NOQUERY-" : query.Templates.Count.ToString()), gn, node);
                if (isTraced)
                {
                    request.writeToLog(s);
                }
                overBudget = true;
                if (!request.IsToplevelRequest)
                {
                    throw new ChatSignalOverBudget(request, s);
                }
            }


            // process the node
            if (ReferenceEquals(null, tagHandlerU))
            {
                childSuccess = true;
                if (node.NodeType == XmlNodeType.Comment)
                {
                    return(Unifiable.Empty);
                }
                if (node.NodeType == XmlNodeType.Text)
                {
                    string s = StaticAIMLUtils.Trim(StaticAIMLUtils.TextNodeValue(node));
                    if (String.IsNullOrEmpty(s))
                    {
                        return(Unifiable.Empty);
                    }
                    return(s);
                }
                // ReSharper disable ConditionIsAlwaysTrueOrFalse
                OutputDelegate del = (request != null) ? request.writeToLog : writeToLog;
                // ReSharper restore ConditionIsAlwaysTrueOrFalse
                if (overBudget)
                {
                    return(Unifiable.Empty);
                }
                string nodeInner = node.InnerXml;
                TargetBot.EvalAiml(node, request, del ?? TextPatternUtils.DEVNULL);
                return(node.InnerXml);
            }

            XmlNode oldNode         = node;
            bool    wasReadonlyNode = oldNode.IsReadOnly;

            // copy the node!?!
            if (protectChild)
            {
                copyParent = true;
                LineInfoElementImpl newnode = StaticAIMLUtils.CopyNode(node, copyParent);
                newnode.ReadOnly = false;
                node             = newnode;
            }

            if (overBudget)
            {
                tagHandlerU.Dispose();
                tagHandlerU  = null;
                childSuccess = true;
                return(Unifiable.Empty);
            }

            tagHandlerU.SetParent(parentHandlerU);
            //if (parent!=null) parent.AddChild(tagHandler);

            Unifiable cp = tagHandlerU.Transform();

            if (Unifiable.IsNullOrEmpty(cp) && (!tagHandlerU.QueryHasSuceeded || tagHandlerU.QueryHasFailed))
            {
                bool needsOneMoreTry = !request.SuspendSearchLimits &&
                                       (request.IsToplevelRequest /*|| result.ParentRequest.IsToplevelRequest*/);
                if (isTraced || needsOneMoreTry)
                {
                    //writeDebugLine("ERROR: Try Again since NULL " + tagHandler);
                    bool wsl = request.SuspendSearchLimits;
                    try
                    {
                        request.SuspendSearchLimits = true;
                        cp = tagHandlerU.Transform();
                        if (Unifiable.IsNull(cp))
                        {
                            childSuccess = false;
                            return(tagHandlerU.GetTemplateNodeInnerText());
                        }
                        if (false && Unifiable.IsNullOrEmpty(cp))
                        {
                            // trace the next line to see why
                            AIMLTagHandler handlerU = tagHandlerU;
                            TargetBot.TraceTest("ERROR: Try Again since NULL " + handlerU,
                                                () => { cp = handlerU.Transform(); });
                        }
                    }
                    finally
                    {
                        request.SuspendSearchLimits = wsl;
                    }
                }
            }
            if (tagHandlerU.QueryHasFailed)
            {
                childSuccess = false;
                return(tagHandlerU.FAIL);
            }
            childSuccess = !tagHandlerU.QueryHasFailed;
            if (!childSuccess)
            {
            }
            var st  = StaticAIMLUtils.IsSilentTag(node);
            var ine = Unifiable.IsNullOrEmpty(cp);

            if (!ine || st)
            {
                childSuccess = true;
                return(cp);
            }
            if (Unifiable.IsNull(cp))
            {
                cp = tagHandlerU.GetTemplateNodeInnerText();
                if (tagHandlerU.QueryHasSuceeded)
                {
                    childSuccess = true;
                    return(cp);
                }
                return(cp);
            }
            return(cp);
        }
        public AIMLTagHandler proccessResponse000(SubQuery query, Request request, Result result,
                                                  XmlNode sOutput, Unifiable sGuard,
                                                  out bool createdOutput, out bool templateSucceeded,
                                                  AIMLTagHandler parentHandlerU, TemplateInfo templateInfo,
                                                  bool copyChild, bool copyParent)
        {
            AltBot Proc = query.TargetBot;

            //query.LastTagHandler = handler;
            bool isTraced = request.IsTraced || request.IsTraced || !request.GraphsAcceptingUserInput ||
                            (templateInfo != null && templateInfo.IsTraced);
            //XmlNode guardNode = AIMLTagHandler.getNode(s.Guard.InnerXml);
            bool usedGuard = sGuard != null && sGuard.PatternNode != null;

            sOutput = sOutput ?? templateInfo.ClonedOutput;
            string  output        = sOutput.OuterXml;
            XmlNode templateNode  = sOutput;
            bool    childOriginal = true;

            result.Started = true;
            if (usedGuard)
            {
                output = "<template>" + sGuard.PatternNode.OuterXml + " GUARDBOM " + output +
                         "</template>";
                templateNode = StaticAIMLUtils.getNodeAndSetSibling(false, output, false, false, sOutput);

                childOriginal = false;
            }

            bool           protectChild     = copyChild || childOriginal;
            bool           suspendingLimits = request.IsToplevelRequest || request.SuspendSearchLimits;
            AIMLTagHandler tagHandlerU      = GetTagHandler(request.Requester, query, request, result,
                                                            templateNode, parentHandlerU);
            string outputSentenceOut = processNode(templateNode, query,
                                                   request, result, request.Requester, parentHandlerU,
                                                   protectChild, copyParent, tagHandlerU, suspendingLimits, out templateSucceeded);

            templateSucceeded = !StaticAIMLUtils.IsFalse(outputSentenceOut);

            if (outputSentenceOut == null)
            {
                if (tagHandlerU == null)
                {
                    writeToLog("tagHandler = null " + output);
                }
                else
                {
                    bool success = false;
                    if (tagHandlerU.QueryHasSuceeded)
                    {
                        success = true;
                    }
                    if (tagHandlerU.QueryHasFailed)
                    {
                        success = false;
                    }
                    if (success)
                    {
                        writeToLog("Very BaD " + output);
                    }
                    else
                    {
                    }
                    templateSucceeded = false;
                    createdOutput     = false;
                    return(tagHandlerU);
                }
            }
            outputSentenceOut = outputSentenceOut ?? "";
            string left, outputSentence;

            if (!StaticAIMLUtils.SplitOff(outputSentenceOut, "GUARDBOM", out left, out outputSentence))
            {
                left           = null;
                outputSentence = outputSentenceOut;
            }
            if (sGuard == null || sGuard.PatternNode != null)
            {
                string o = Proc.ToEnglish(outputSentence);
                if (outputSentence.Trim().Length > 0)
                {
                    templateSucceeded = true;
                }
                if (Proc.IsOutputSentence(o, outputSentence))
                {
                    if (isTraced)
                    {
                        string aIMLLoaderParentTextAndSourceInfo = ParentTextAndSourceInfo(templateNode);
                        if (aIMLLoaderParentTextAndSourceInfo.Length > 300)
                        {
                            aIMLLoaderParentTextAndSourceInfo = TextFilter.ClipString(
                                aIMLLoaderParentTextAndSourceInfo, 300);
                        }
                        writeToLog("AIMLTRACE '{0}' IsOutputSentence={1}", o, aIMLLoaderParentTextAndSourceInfo);
                    }
                    createdOutput = true;
                    request.AddOutputSentences(templateInfo, o, result, request.TopLevelScore);
                }
                else
                {
                    createdOutput = false;
                }
                // @TODO @HACK @BUG isTraced is a HORRID flag here!
                if (false && !createdOutput && isTraced && request.GraphsAcceptingUserInput)
                {
                    if (templateInfo != null)
                    {
                        string fromStr = " from " + templateInfo.Graph;
                        if (!StaticAIMLUtils.IsSilentTag(templateNode))
                        {
                            writeToLog("SILENT '{0}' TEMPLATE={1}", o, ParentTextAndSourceInfo(templateNode) + fromStr);
                        }
                        request.DisableTemplateUntilFinished(templateInfo);
                    }
                    else
                    {
                        writeToLog("UNUSED '{0}' TEMPLATE={1}", o, ParentTextAndSourceInfo(templateNode));
                    }
                }

                return(tagHandlerU);
            }
            try
            {
                templateSucceeded = !StaticAIMLUtils.IsFalse(left);
                if (!templateSucceeded)
                {
                    createdOutput = false;
                    return(tagHandlerU);
                }
                string lang = StaticXMLUtils.GetAttribValue(sGuard.PatternNode, "lang", "cycl").ToLower();

                try
                {
                    Unifiable ss = Proc.SystemExecute(left, lang, request);
                    if (StaticAIMLUtils.IsFalse(ss) || StaticAIMLUtils.IsNullOrEmpty(ss))
                    {
                        if (isTraced)
                        {
                            writeToLog("GUARD FALSE '{0}' TEMPLATE={1}", request,
                                       ParentTextAndSourceInfo(templateNode));
                        }
                        templateSucceeded = false;
                        createdOutput     = false;
                        return(tagHandlerU);
                    }
                    else
                    {
                        templateSucceeded = true;
                    }
                }
                catch (ChatSignal e)
                {
                    throw;
                }
                catch (Exception e)
                {
                    Proc.writeToLog(e);
                    templateSucceeded = false;
                    createdOutput     = false;
                    return(tagHandlerU);
                }

                //part the BOM
                string o = Proc.ToEnglish(outputSentence);
                if (Proc.IsOutputSentence(o, outputSentence))
                {
                    if (isTraced)
                    {
                        writeToLog(query.Graph + ": GUARD SUCCESS '{0}' TEMPLATE={1}", o,
                                   ParentTextAndSourceInfo(templateNode));
                    }
                    templateSucceeded = true;
                    createdOutput     = true;
                    request.AddOutputSentences(templateInfo, o, result, request.TopLevelScore);
                    return(tagHandlerU);
                }
                else
                {
                    writeToLog("GUARD SKIP '{0}' TEMPLATE={1}", outputSentence,
                               ParentTextAndSourceInfo(templateNode));
                }
                templateSucceeded = false;
                createdOutput     = false;
                return(tagHandlerU);
            }
            catch (ChatSignal e)
            {
                throw;
            }
            catch (Exception ex)
            {
                Proc.writeToLog(ex);
                templateSucceeded = false;
                createdOutput     = false;
                return(tagHandlerU);
            }
        }