public MainDialog( IServiceProvider serviceProvider, IBotTelemetryClient telemetryClient, MicrosoftAppCredentials appCredentials, ProactiveState proactiveState) : base(nameof(MainDialog), telemetryClient) { _services = serviceProvider.GetService <BotServices>(); _settings = serviceProvider.GetService <BotSettings>(); _templateEngine = serviceProvider.GetService <LocaleTemplateEngineManager>(); TelemetryClient = telemetryClient; // Create user state properties var userState = serviceProvider.GetService <UserState>(); _userProfileState = userState.CreateProperty <UserProfileState>(nameof(UserProfileState)); _skillContext = userState.CreateProperty <SkillContext>(nameof(SkillContext)); // Create conversation state properties var conversationState = serviceProvider.GetService <ConversationState>(); _previousResponseAccessor = conversationState.CreateProperty <List <Activity> >(StateProperties.PreviousBotResponse); // SAMPLE: Create proactive state properties _appCredentials = appCredentials; _proactiveStateAccessor = proactiveState.CreateProperty <ProactiveModel>(nameof(ProactiveModel)); // Register dialogs _onboardingDialog = serviceProvider.GetService <OnboardingDialog>(); _switchSkillDialog = serviceProvider.GetService <SwitchSkillDialog>(); AddDialog(_onboardingDialog); AddDialog(_switchSkillDialog); // Register a QnAMakerDialog for each registered knowledgebase and ensure localised responses are provided. var localizedServices = _services.GetCognitiveModels(); foreach (var knowledgebase in localizedServices.QnAConfiguration) { var qnaDialog = new QnAMakerDialog( knowledgeBaseId: knowledgebase.Value.KnowledgeBaseId, endpointKey: knowledgebase.Value.EndpointKey, hostName: knowledgebase.Value.Host, noAnswer: _templateEngine.GenerateActivityForLocale("UnsupportedMessage"), activeLearningCardTitle: _templateEngine.GenerateActivityForLocale("QnaMakerAdaptiveLearningCardTitle").Text, cardNoMatchText: _templateEngine.GenerateActivityForLocale("QnaMakerNoMatchText").Text) { Id = knowledgebase.Key }; AddDialog(qnaDialog); } // Register skill dialogs var skillDialogs = serviceProvider.GetServices <SkillDialog>(); foreach (var dialog in skillDialogs) { AddDialog(dialog); } }
public MainDialog( IServiceProvider serviceProvider, IBotTelemetryClient telemetryClient) : base(nameof(MainDialog)) { _services = serviceProvider.GetService <BotServices>(); _settings = serviceProvider.GetService <BotSettings>(); _templateEngine = serviceProvider.GetService <LocaleTemplateEngineManager>(); _skillsConfig = serviceProvider.GetService <SkillsConfiguration>(); TelemetryClient = telemetryClient; var conversationState = serviceProvider.GetService <ConversationState>(); _previousResponseAccessor = conversationState.CreateProperty <List <Activity> >(StateProperties.PreviousBotResponse); var steps = new WaterfallStep[] { RouteStepAsync, }; AddDialog(new WaterfallDialog(nameof(MainDialog), steps)); AddDialog(new TextPrompt(nameof(TextPrompt))); InitialDialogId = nameof(MainDialog); // Register dialogs _switchSkillDialog = serviceProvider.GetService <TeamsSwitchSkillDialog>(); AddDialog(_switchSkillDialog); // Register a QnAMakerDialog for each registered knowledgebase and ensure localised responses are provided. var localizedServices = _services.GetCognitiveModels(); foreach (var knowledgebase in localizedServices.QnAConfiguration) { var qnaDialog = new QnAMakerDialog( knowledgeBaseId: knowledgebase.Value.KnowledgeBaseId, endpointKey: knowledgebase.Value.EndpointKey, hostName: knowledgebase.Value.Host, noAnswer: _templateEngine.GenerateActivityForLocale("UnsupportedMessage"), activeLearningCardTitle: _templateEngine.GenerateActivityForLocale("QnaMakerAdaptiveLearningCardTitle").Text, cardNoMatchText: _templateEngine.GenerateActivityForLocale("QnaMakerNoMatchText").Text) { Id = knowledgebase.Key }; AddDialog(qnaDialog); } // Register skill dialogs var skillDialogs = serviceProvider.GetServices <TeamsSkillDialog>(); foreach (var dialog in skillDialogs) { AddDialog(dialog); } }
public void GetResponseWithLanguageGeneration_English() { CultureInfo.CurrentUICulture = new CultureInfo("en-us"); // Generate English response using LG with data dynamic data = new JObject(); data.Name = "Darren"; var response = localeTemplateEngineManager.GenerateActivityForLocale("HaveNameMessage", data); // Retrieve possible responses directly from the correct template to validate logic var possibleResponses = localeTemplateEngineManager.TemplateEnginesPerLocale["en-us"].ExpandTemplate("HaveNameMessage", data); Assert.IsTrue(possibleResponses.Contains(response.Text)); }
public DefaultAdapter( BotSettings settings, LocaleTemplateEngineManager templateEngine, ConversationState conversationState, ICredentialProvider credentialProvider, TelemetryInitializerMiddleware telemetryMiddleware, IBotTelemetryClient telemetryClient) : base(credentialProvider) { OnTurnError = async(turnContext, exception) => { await turnContext.SendActivityAsync(new Activity(type : ActivityTypes.Trace, text : $"Exception Message: {exception.Message}, Stack: {exception.StackTrace}")); await turnContext.SendActivityAsync(templateEngine.GenerateActivityForLocale("ErrorMessage")); telemetryClient.TrackException(exception); }; Use(telemetryMiddleware); // Uncomment the following line for local development without Azure Storage // Use(new TranscriptLoggerMiddleware(new MemoryTranscriptStore())); Use(new TranscriptLoggerMiddleware(new AzureBlobTranscriptStore(settings.BlobStorage.ConnectionString, settings.BlobStorage.Container))); Use(new ShowTypingMiddleware()); Use(new FeedbackMiddleware(conversationState, telemetryClient)); Use(new SetLocaleMiddleware(settings.DefaultLocale ?? "en-us")); Use(new EventDebuggerMiddleware()); }
public CustomSkillAdapter( BotSettings settings, UserState userState, ConversationState conversationState, LocaleTemplateEngineManager templateEngine, TelemetryInitializerMiddleware telemetryMiddleware, IBotTelemetryClient telemetryClient) : base(null, telemetryClient) { OnTurnError = async(turnContext, exception) => { await turnContext.SendActivityAsync(new Activity(type : ActivityTypes.Trace, text : $"Exception Message: {exception.Message}, Stack: {exception.StackTrace}")); await turnContext.SendActivityAsync(templateEngine.GenerateActivityForLocale("ErrorMessage")); telemetryClient.TrackException(exception); }; Use(telemetryMiddleware); // Uncomment the following line for local development without Azure Storage // Use(new TranscriptLoggerMiddleware(new MemoryTranscriptStore())); Use(new TranscriptLoggerMiddleware(new AzureBlobTranscriptStore(settings.BlobStorage.ConnectionString, settings.BlobStorage.Container))); Use(new TelemetryLoggerMiddleware(telemetryClient, logPersonalInformation: true)); Use(new SetLocaleMiddleware(settings.DefaultLocale ?? "en-us")); Use(new EventDebuggerMiddleware()); Use(new SkillMiddleware(userState, conversationState, conversationState.CreateProperty <DialogState>(nameof(DialogState)))); }
protected override async Task OnMembersAddedAsync(IList <ChannelAccount> membersAdded, ITurnContext <IConversationUpdateActivity> turnContext, CancellationToken cancellationToken) { var userProfile = await _userProfileState.GetAsync(turnContext, () => new UserProfileState()); if (string.IsNullOrEmpty(userProfile.Name)) { // Send new user intro card. await turnContext.SendActivityAsync(_templateEngine.GenerateActivityForLocale("NewUserIntroCard", userProfile)); } else { // Send returning user intro card. await turnContext.SendActivityAsync(_templateEngine.GenerateActivityForLocale("ReturningUserIntroCard", userProfile)); } await _dialog.RunAsync(turnContext, _dialogStateAccessor, cancellationToken); }
// Runs on every turn of the conversation to check if the conversation should be interrupted. protected override async Task <InterruptionAction> OnInterruptDialogAsync(DialogContext dc, CancellationToken cancellationToken) { var activity = dc.Context.Activity; if (activity.Type == ActivityTypes.Message && !string.IsNullOrEmpty(activity.Text)) { // Get connected LUIS result from turn state. var generalResult = dc.Context.TurnState.Get <GeneralLuis>(StateProperties.GeneralLuisResult); (var generalIntent, var generalScore) = generalResult.TopIntent(); if (generalScore > 0.5) { switch (generalIntent) { case GeneralLuis.Intent.Cancel: { await dc.Context.SendActivityAsync(_templateEngine.GenerateActivityForLocale("CancelledMessage")); await dc.CancelAllDialogsAsync(); return(InterruptionAction.End); } case GeneralLuis.Intent.Help: { await dc.Context.SendActivityAsync(_templateEngine.GenerateActivityForLocale("HelpMessage")); return(InterruptionAction.Resume); } case GeneralLuis.Intent.Logout: { // Log user out of all accounts. await LogUserOut(dc); await dc.Context.SendActivityAsync(_templateEngine.GenerateActivityForLocale("LogoutMessage")); return(InterruptionAction.End); } } } } return(InterruptionAction.NoAction); }
protected override async Task <DialogTurnResult> OnBeginDialogAsync(DialogContext innerDc, object options, CancellationToken cancellationToken = default) { if (innerDc.Context.Activity.Type == ActivityTypes.Message) { if (innerDc.Context.Activity.Conversation?.IsGroup == true) { // Remove bot atmentions for teams/groupchat scope innerDc.Context.Activity.RemoveRecipientMention(); // If bot is invoked without any text, reply with FirstPromptMessage if (string.IsNullOrWhiteSpace(innerDc.Context.Activity.Text)) { await innerDc.Context.SendActivityAsync(_templateEngine.GenerateActivityForLocale("FirstPromptMessage")); return(EndOfTurn); } } // Get cognitive models for the current locale. var localizedServices = _services.GetCognitiveModels(); // Run LUIS recognition and store result in turn state. var dispatchResult = await localizedServices.DispatchService.RecognizeAsync <DispatchLuis>(innerDc.Context, cancellationToken); innerDc.Context.TurnState.Add(StateProperties.DispatchResult, dispatchResult); if (dispatchResult.TopIntent().intent == DispatchLuis.Intent.l_General) { // Run LUIS recognition on General model and store result in turn state. var generalResult = await localizedServices.LuisServices["General"].RecognizeAsync <GeneralLuis>(innerDc.Context, cancellationToken); innerDc.Context.TurnState.Add(StateProperties.GeneralResult, generalResult); } // Check for any interruptions var interrupted = await InterruptDialogAsync(innerDc, cancellationToken); if (interrupted) { // If dialog was interrupted, return EndOfTurn return(EndOfTurn); } } // Set up response caching for "repeat" functionality. innerDc.Context.OnSendActivities(StoreOutgoingActivities); return(await base.OnBeginDialogAsync(innerDc, options, cancellationToken)); }
// Runs on every turn of the conversation to check if the conversation should be interrupted. protected async Task <bool> InterruptDialogAsync(DialogContext innerDc, CancellationToken cancellationToken) { var interrupted = false; var activity = innerDc.Context.Activity; if (activity.Type == ActivityTypes.Message && !string.IsNullOrEmpty(activity.Text)) { // Get connected LUIS result from turn state. var generalResult = innerDc.Context.TurnState.Get <General>(StateProperties.GeneralLuisResultKey); (var generalIntent, var generalScore) = generalResult.TopIntent(); if (generalScore > 0.5) { switch (generalIntent) { case General.Intent.Cancel: { await innerDc.Context.SendActivityAsync(_templateEngine.GenerateActivityForLocale(ToDoMainResponses.CancelMessage)); await innerDc.CancelAllDialogsAsync(); await innerDc.BeginDialogAsync(InitialDialogId); interrupted = true; break; } case General.Intent.Help: { await innerDc.Context.SendActivityAsync(_templateEngine.GenerateActivityForLocale(ToDoMainResponses.HelpMessage)); await innerDc.RepromptDialogAsync(); interrupted = true; break; } case General.Intent.Logout: { // Log user out of all accounts. await LogUserOut(innerDc); await innerDc.Context.SendActivityAsync(_templateEngine.GenerateActivityForLocale(ToDoMainResponses.LogOut)); await innerDc.CancelAllDialogsAsync(); await innerDc.BeginDialogAsync(InitialDialogId); interrupted = true; break; } } } } return(interrupted); }
// Invoked when a "task/fetch" event is received to invoke task module. protected override async Task <TaskModuleResponse> OnTeamsTaskModuleFetchAsync(ITurnContext <IInvokeActivity> turnContext, TaskModuleRequest taskModuleRequest, CancellationToken cancellationToken) { try { string skillId = (turnContext.Activity as Activity).GetSkillId(); var skill = _skillsConfig.Skills.Where(s => s.Value.AppId == skillId).FirstOrDefault().Value; // Forward request to correct skill var invokeResponse = await _skillHttpClient.PostActivityAsync(this._appId, skill, _skillsConfig.SkillHostEndpoint, turnContext.Activity as Activity, cancellationToken); return(invokeResponse.GetTaskModuleRespose()); } catch (Exception exception) { await turnContext.SendActivityAsync(_templateEngine.GenerateActivityForLocale("ErrorMessage")); _telemetryClient.TrackException(exception); return(null); } }
public DefaultAdapter( BotSettings settings, UserState userState, ConversationState conversationState, IChannelProvider channelProvider, ICredentialProvider credentialProvider, LocaleTemplateEngineManager templateEngine, TelemetryInitializerMiddleware telemetryMiddleware, IBotTelemetryClient telemetryClient) : base(credentialProvider, channelProvider) { OnTurnError = async(turnContext, exception) => { await turnContext.SendActivityAsync(new Activity(type : ActivityTypes.Trace, text : $"Exception Message: {exception.Message}, Stack: {exception.StackTrace}")); await turnContext.SendActivityAsync(templateEngine.GenerateActivityForLocale("ErrorMessage")); telemetryClient.TrackException(exception); if (turnContext.IsSkill()) { // Send and EndOfConversation activity to the skill caller with the error to end the conversation // and let the caller decide what to do. var endOfConversation = Activity.CreateEndOfConversationActivity(); endOfConversation.Code = "SkillError"; endOfConversation.Text = exception.Message; await turnContext.SendActivityAsync(endOfConversation); } }; Use(telemetryMiddleware); // Uncomment the following line for local development without Azure Storage // Use(new TranscriptLoggerMiddleware(new MemoryTranscriptStore())); Use(new TranscriptLoggerMiddleware(new AzureBlobTranscriptStore(settings.BlobStorage.ConnectionString, settings.BlobStorage.Container))); Use(new TelemetryLoggerMiddleware(telemetryClient, logPersonalInformation: true)); Use(new ShowTypingMiddleware()); Use(new SetLocaleMiddleware(settings.DefaultLocale ?? "en-us")); Use(new EventDebuggerMiddleware()); Use(new SkillMiddleware(userState, conversationState, conversationState.CreateProperty <DialogState>(nameof(DialogState)))); Use(new SetSpeakMiddleware()); }
public DefaultAdapter( BotSettings settings, UserState userState, ConversationState conversationState, ICredentialProvider credentialProvider, IBotTelemetryClient telemetryClient, LocaleTemplateEngineManager localeTemplateEngineManager, TelemetryInitializerMiddleware telemetryMiddleware) : base(credentialProvider) { OnTurnError = async(context, exception) => { var activity = localeTemplateEngineManager.GenerateActivityForLocale(ToDoSharedResponses.ToDoErrorMessage, context); await context.SendActivityAsync(activity); await context.SendActivityAsync(new Activity(type : ActivityTypes.Trace, text : $"To Do Skill Error: {exception.Message} | {exception.StackTrace}")); telemetryClient.TrackException(exception); if (context.IsSkill()) { // Send and EndOfConversation activity to the skill caller with the error to end the conversation // and let the caller decide what to do. var endOfConversation = Activity.CreateEndOfConversationActivity(); endOfConversation.Code = "SkillError"; endOfConversation.Text = exception.Message; await context.SendActivityAsync(endOfConversation); } }; Use(telemetryMiddleware); Use(new TranscriptLoggerMiddleware(new AzureBlobTranscriptStore(settings.BlobStorage.ConnectionString, settings.BlobStorage.Container))); Use(new TelemetryLoggerMiddleware(telemetryClient, logPersonalInformation: true)); Use(new ShowTypingMiddleware()); Use(new SetLocaleMiddleware(settings.DefaultLocale ?? "en-us")); Use(new EventDebuggerMiddleware()); Use(new SkillMiddleware(userState, conversationState, conversationState.CreateProperty <DialogState>(nameof(DialogState)))); Use(new SetSpeakMiddleware()); }
protected override async Task OnMembersAddedAsync(IList <ChannelAccount> membersAdded, ITurnContext <IConversationUpdateActivity> turnContext, CancellationToken cancellationToken) { await turnContext.SendActivityAsync(_templateEngine.GenerateActivityForLocale("IntroMessage")); await _dialog.RunAsync(turnContext, _dialogStateAccessor, cancellationToken); }
public MainDialog( IServiceProvider serviceProvider, IBotTelemetryClient telemetryClient) : base(nameof(MainDialog), serviceProvider, telemetryClient) { _services = serviceProvider.GetService <BotServices>(); _settings = serviceProvider.GetService <BotSettings>(); _templateEngine = serviceProvider.GetService <LocaleTemplateEngineManager>(); _skillsConfig = serviceProvider.GetService <SkillsConfiguration>(); var userState = serviceProvider.GetService <UserState>(); _userProfileState = userState.CreateProperty <UserProfileState>(nameof(UserProfileState)); var conversationState = serviceProvider.GetService <ConversationState>(); _previousResponseAccessor = conversationState.CreateProperty <List <Activity> >(StateProperties.PreviousBotResponse); WaterfallStep[] steps = SetupWaterfallSteps(); AddDialog(new WaterfallDialog(nameof(MainDialog), steps)); AddDialog(new TextPrompt(nameof(TextPrompt))); AddDialog(new ChoicePrompt(nameof(ChoicePrompt)) { Style = ListStyle.HeroCard }); InitialDialogId = nameof(MainDialog); // Register dialogs _oauthPrompt = serviceProvider.GetService <OAuthPrompt>(); _loginDialog = serviceProvider.GetService <LoginDialog>(); _onboardingDialog = serviceProvider.GetService <OnboardingDialog>(); _switchSkillDialog = serviceProvider.GetService <SwitchSkillDialog>(); _escalateDialog = serviceProvider.GetService <EscalateDialog>(); _cancelDialog = serviceProvider.GetService <CancelDialog>(); _entertainDialog = serviceProvider.GetService <EntertainDialog>(); _chitchatdialog = serviceProvider.GetService <ChitchatDialog>(); _stressDialog = serviceProvider.GetService <StressDialog>(); _highstresshandlingDialog = serviceProvider.GetService <HighStressHandlingDialog>(); _stresshandlingDialog = serviceProvider.GetService <StressHandlingDialog>(); _journalingDialog = serviceProvider.GetService <JournalingDialog>(); AddDialog(_oauthPrompt); AddDialog(_loginDialog); AddDialog(_onboardingDialog); AddDialog(_switchSkillDialog); AddDialog(_escalateDialog); AddDialog(_cancelDialog); AddDialog(_entertainDialog); AddDialog(_chitchatdialog); AddDialog(_stressDialog); AddDialog(_highstresshandlingDialog); AddDialog(_stresshandlingDialog); AddDialog(_journalingDialog); // Register a QnAMakerDialog for each registered knowledgebase and ensure localised responses are provided. var localizedServices = _services.GetCognitiveModels(); foreach (var knowledgebase in localizedServices.QnAConfiguration) { var qnaDialog = new QnAMakerDialog( knowledgeBaseId: knowledgebase.Value.KnowledgeBaseId, endpointKey: knowledgebase.Value.EndpointKey, hostName: knowledgebase.Value.Host, noAnswer: _templateEngine.GenerateActivityForLocale("UnsupportedMessage"), activeLearningCardTitle: _templateEngine.GenerateActivityForLocale("QnaMakerAdaptiveLearningCardTitle").Text, cardNoMatchText: _templateEngine.GenerateActivityForLocale("QnaMakerNoMatchText").Text) { Id = knowledgebase.Key }; AddDialog(qnaDialog); } // Register skill dialogs var skillDialogs = serviceProvider.GetServices <SkillDialog>(); foreach (var dialog in skillDialogs) { AddDialog(dialog); } }
private async Task <bool> InterruptDialogAsync(DialogContext innerDc, CancellationToken cancellationToken) { var interrupted = false; var activity = innerDc.Context.Activity; var userProfile = await _userProfileState.GetAsync(innerDc.Context, () => new UserProfileState()); var dialog = innerDc.ActiveDialog?.Id != null?innerDc.FindDialog(innerDc.ActiveDialog?.Id) : null; if (activity.Type == ActivityTypes.Message && !string.IsNullOrEmpty(activity.Text)) { // Check if the active dialog is a skill for conditional interruption. var isSkill = dialog is SkillDialog; // Get Dispatch LUIS result from turn state. var dispatchResult = innerDc.Context.TurnState.Get <DispatchLuis>(StateProperties.DispatchResult); (var dispatchIntent, var dispatchScore) = dispatchResult.TopIntent(); // Check if we need to switch skills. if (isSkill && IsSkillIntent(dispatchIntent) && dispatchIntent.ToString() != dialog.Id && dispatchScore > 0.9) { EnhancedBotFrameworkSkill identifiedSkill; if (_skillsConfig.Skills.TryGetValue(dispatchIntent.ToString(), out identifiedSkill)) { var prompt = _templateEngine.GenerateActivityForLocale("SkillSwitchPrompt", new { Skill = identifiedSkill.Name }); await innerDc.BeginDialogAsync(_switchSkillDialog.Id, new SwitchSkillDialogOptions(prompt, identifiedSkill)); interrupted = true; } else { throw new ArgumentException($"{dispatchIntent.ToString()} is not in the skills configuration"); } } if (dispatchIntent == DispatchLuis.Intent.l_General) { // Get connected LUIS result from turn state. var generalResult = innerDc.Context.TurnState.Get <GeneralLuis>(StateProperties.GeneralResult); (var generalIntent, var generalScore) = generalResult.TopIntent(); if (generalScore > 0.5) { switch (generalIntent) { case GeneralLuis.Intent.Cancel: { await innerDc.Context.SendActivityAsync(_templateEngine.GenerateActivityForLocale("CancelledMessage", userProfile)); await innerDc.CancelAllDialogsAsync(); await innerDc.BeginDialogAsync(InitialDialogId); interrupted = true; break; } case GeneralLuis.Intent.Escalate: { await innerDc.Context.SendActivityAsync(_templateEngine.GenerateActivityForLocale("EscalateMessage", userProfile)); await innerDc.RepromptDialogAsync(); interrupted = true; break; } case GeneralLuis.Intent.Help: { if (!isSkill) { // If current dialog is a skill, allow it to handle its own help intent. await innerDc.Context.SendActivityAsync(_templateEngine.GenerateActivityForLocale("HelpCard", userProfile)); await innerDc.RepromptDialogAsync(); interrupted = true; } break; } case GeneralLuis.Intent.Logout: { // Log user out of all accounts. await LogUserOut(innerDc); await innerDc.Context.SendActivityAsync(_templateEngine.GenerateActivityForLocale("LogoutMessage", userProfile)); await innerDc.CancelAllDialogsAsync(); await innerDc.BeginDialogAsync(InitialDialogId); interrupted = true; break; } case GeneralLuis.Intent.Repeat: { // Sends the activities since the last user message again. var previousResponse = await _previousResponseAccessor.GetAsync(innerDc.Context, () => new List <Activity>()); foreach (var response in previousResponse) { // Reset id of original activity so it can be processed by the channel. response.Id = string.Empty; await innerDc.Context.SendActivityAsync(response); } interrupted = true; break; } case GeneralLuis.Intent.StartOver: { await innerDc.Context.SendActivityAsync(_templateEngine.GenerateActivityForLocale("StartOverMessage", userProfile)); // Cancel all dialogs on the stack. await innerDc.CancelAllDialogsAsync(); await innerDc.BeginDialogAsync(InitialDialogId); interrupted = true; break; } case GeneralLuis.Intent.Stop: { // Use this intent to send an event to your device that can turn off the microphone in speech scenarios. break; } case GeneralLuis.Intent.Stress: { await innerDc.BeginDialogAsync(nameof(StressDialog)); interrupted = true; break; } case GeneralLuis.Intent.UpdateProfile: { await innerDc.BeginDialogAsync(nameof(OnboardingDialog)); interrupted = true; break; } } } } } return(interrupted); }