private async Task <bool> QueueFirstMatchAsync(SequenceContext sequenceContext, DialogEvent dialogEvent, bool preBubble, CancellationToken cancellationToken)
        {
            var selection = await Selector.Select(sequenceContext, cancellationToken).ConfigureAwait(false);

            if (selection.Any())
            {
                var evt = Triggers[selection.First()];
                await sequenceContext.DebuggerStepAsync(evt, dialogEvent, cancellationToken).ConfigureAwait(false);

                Trace.TraceInformation($"Executing Dialog: {Id} Rule[{selection}]: {evt.GetType().Name}: {evt.GetExpression(new ExpressionEngine())}");
                var changes = await evt.ExecuteAsync(sequenceContext).ConfigureAwait(false);

                if (changes != null && changes.Count > 0)
                {
                    sequenceContext.QueueChanges(changes[0]);
                    return(true);
                }
            }

            return(false);
        }
        protected async Task <bool> ProcessEventAsync(SequenceContext sequenceContext, DialogEvent dialogEvent, bool preBubble, CancellationToken cancellationToken = default)
        {
            // Save into turn
            sequenceContext.GetState().SetValue(TurnPath.DIALOGEVENT, dialogEvent);

            EnsureDependenciesInstalled();

            // Look for triggered evt
            var handled = await QueueFirstMatchAsync(sequenceContext, dialogEvent, preBubble, cancellationToken).ConfigureAwait(false);

            if (handled)
            {
                return(true);
            }

            // Default processing
            if (preBubble)
            {
                switch (dialogEvent.Name)
                {
                case AdaptiveEvents.BeginDialog:
                    if (sequenceContext.GetState().GetBoolValue(TurnPath.ACTIVITYPROCESSED) == false)
                    {
                        // Emit leading ActivityReceived event
                        var activityReceivedEvent = new DialogEvent()
                        {
                            Name   = AdaptiveEvents.ActivityReceived,
                            Value  = sequenceContext.Context.Activity,
                            Bubble = false
                        };

                        handled = await ProcessEventAsync(sequenceContext, dialogEvent : activityReceivedEvent, preBubble : true, cancellationToken : cancellationToken).ConfigureAwait(false);
                    }

                    break;

                case AdaptiveEvents.ActivityReceived:

                    if (sequenceContext.Context.Activity.Type == ActivityTypes.Message)
                    {
                        // Recognize utterance (ignore handled)
                        var recognizeUtteranceEvent = new DialogEvent
                        {
                            Name   = AdaptiveEvents.RecognizeUtterance,
                            Value  = sequenceContext.Context.Activity,
                            Bubble = false
                        };
                        await ProcessEventAsync(sequenceContext, dialogEvent : recognizeUtteranceEvent, preBubble : true, cancellationToken : cancellationToken).ConfigureAwait(false);

                        // Emit leading RecognizedIntent event
                        var recognized            = sequenceContext.GetState().GetValue <RecognizerResult>(TurnPath.RECOGNIZED);
                        var recognizedIntentEvent = new DialogEvent
                        {
                            Name   = AdaptiveEvents.RecognizedIntent,
                            Value  = recognized,
                            Bubble = false
                        };
                        handled = await ProcessEventAsync(sequenceContext, dialogEvent : recognizedIntentEvent, preBubble : true, cancellationToken : cancellationToken).ConfigureAwait(false);
                    }

                    // Has an interruption occured?
                    // - Setting this value to true causes any running inputs to re-prompt when they're
                    //   continued.  The developer can clear this flag if they want the input to instead
                    //   process the users uterrance when its continued.
                    if (handled)
                    {
                        sequenceContext.GetState().SetValue(TurnPath.INTERRUPTED, true);
                    }

                    break;

                case AdaptiveEvents.RecognizeUtterance:

                    if (sequenceContext.Context.Activity.Type == ActivityTypes.Message)
                    {
                        // Recognize utterance
                        var recognized = await OnRecognize(sequenceContext, cancellationToken).ConfigureAwait(false);

                        sequenceContext.GetState().SetValue(TurnPath.RECOGNIZED, recognized);

                        var(name, score) = recognized.GetTopScoringIntent();
                        sequenceContext.GetState().SetValue(TurnPath.TOPINTENT, name);
                        sequenceContext.GetState().SetValue(TurnPath.TOPSCORE, score);

                        if (Recognizer != null)
                        {
                            await sequenceContext.DebuggerStepAsync(Recognizer, AdaptiveEvents.RecognizeUtterance, cancellationToken).ConfigureAwait(false);
                        }

                        handled = true;
                    }

                    break;
                }
            }
            else
            {
                switch (dialogEvent.Name)
                {
                case AdaptiveEvents.BeginDialog:
                    if (sequenceContext.GetState().GetBoolValue(TurnPath.ACTIVITYPROCESSED) == false)
                    {
                        var activityReceivedEvent = new DialogEvent
                        {
                            Name   = AdaptiveEvents.ActivityReceived,
                            Value  = sequenceContext.Context.Activity,
                            Bubble = false
                        };

                        handled = await ProcessEventAsync(sequenceContext, dialogEvent : activityReceivedEvent, preBubble : false, cancellationToken : cancellationToken).ConfigureAwait(false);
                    }

                    break;

                case AdaptiveEvents.ActivityReceived:

                    var activity = sequenceContext.Context.Activity;

                    if (activity.Type == ActivityTypes.Message)
                    {
                        // Empty sequence?
                        if (!sequenceContext.Actions.Any())
                        {
                            // Emit trailing unknownIntent event
                            var unknownIntentEvent = new DialogEvent
                            {
                                Name   = AdaptiveEvents.UnknownIntent,
                                Bubble = false
                            };
                            handled = await ProcessEventAsync(sequenceContext, dialogEvent : unknownIntentEvent, preBubble : false, cancellationToken : cancellationToken).ConfigureAwait(false);
                        }
                        else
                        {
                            handled = false;
                        }
                    }

                    // Has an interruption occured?
                    // - Setting this value to true causes any running inputs to re-prompt when they're
                    //   continued.  The developer can clear this flag if they want the input to instead
                    //   process the users uterrance when its continued.
                    if (handled)
                    {
                        sequenceContext.GetState().SetValue(TurnPath.INTERRUPTED, true);
                    }

                    break;
                }
            }

            return(handled);
        }