We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[bug] ShowTypingMiddleware middleware in a python bot not functioning
## Version
`botbuilder-core        4.7.1`  
`botbuilder-schema      4.7.1`

## Describe the bug


``` python
#app.py 
ADAPTER = BotFrameworkAdapter(SETTINGS)
# show typing indicator on long activities
ADAPTER.use(ShowTypingMiddleware(delay=0.5, period=2.0))
```

``` python
#bot.py 
...

    async def on_message_activity(self, turn_context: TurnContext):
        if turn_context.activity.text == "middleware":
            await asyncio.sleep(10) # mock getting some data 
            await turn_context.send_activity("done")

...
```

## Expected behavior

I expect that calling the middleware 
- shows a TI for activities taking longer than .5 seconds 
- repeat sending a TI to the client every 2 seconds 

## Actual results :  

 - TI is sent one time only
 - no repeat TI are sent 
 - a runtime warning is shown:
```
 c:\develop\x\pybot1\.venv\lib\site-packages\botbuilder\core\show_typing_middleware.py:79: 
RuntimeWarning: coroutine 'ShowTypingMiddleware.on_turn.<locals>.start_interval' was never awaited
  start_interval(context, period, period)
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
```

In the emulator log it is clear that only one TI indicator is sent , and no repeats are to be seen
```
[16:55:12]<- messageYou said 'middleware'
[16:55:12]POST200conversations.:conversationId.activities.:activityId
[16:55:12]POST201directline.conversations.:conversationId.activities
[16:55:43]-> messagemiddleware
[16:55:44]<- typing
[16:55:44]POST200conversations.:conversationId.activities.:activityId
[16:55:54]<- messagedone
[16:55:54]POST200conversations.:conversationId.activities.:activityId
[16:55:54]POST201directline.conversations.:conversationId.activities
```

## Additional context
also see Question on [SO](https://stackoverflow.com/posts/60467080/edit)


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `libraries/botbuilder-core/botbuilder/core/show_typing_middleware.py`
Content:
```
1 # Copyright (c) Microsoft Corporation. All rights reserved.
2 # Licensed under the MIT License.
3 
4 import time
5 from functools import wraps
6 from typing import Awaitable, Callable
7 
8 from botbuilder.schema import Activity, ActivityTypes
9 
10 from .middleware_set import Middleware
11 from .turn_context import TurnContext
12 
13 
14 def delay(span=0.0):
15     def wrap(func):
16         @wraps(func)
17         async def delayed():
18             time.sleep(span)
19             await func()
20 
21         return delayed
22 
23     return wrap
24 
25 
26 class Timer:
27     clear_timer = False
28 
29     async def set_timeout(self, func, time):
30         is_invocation_cancelled = False
31 
32         @delay(time)
33         async def some_fn():  # pylint: disable=function-redefined
34             if not self.clear_timer:
35                 await func()
36 
37         await some_fn()
38         return is_invocation_cancelled
39 
40     def set_clear_timer(self):
41         self.clear_timer = True
42 
43 
44 class ShowTypingMiddleware(Middleware):
45     def __init__(self, delay: float = 0.5, period: float = 2.0):
46         if delay < 0:
47             raise ValueError("Delay must be greater than or equal to zero")
48 
49         if period <= 0:
50             raise ValueError("Repeat period must be greater than zero")
51 
52         self._delay = delay
53         self._period = period
54 
55     async def on_turn(
56         self, context: TurnContext, logic: Callable[[TurnContext], Awaitable]
57     ):
58         finished = False
59         timer = Timer()
60 
61         async def start_interval(context: TurnContext, delay: int, period: int):
62             async def aux():
63                 if not finished:
64                     typing_activity = Activity(
65                         type=ActivityTypes.typing,
66                         relates_to=context.activity.relates_to,
67                     )
68 
69                     conversation_reference = TurnContext.get_conversation_reference(
70                         context.activity
71                     )
72 
73                     typing_activity = TurnContext.apply_conversation_reference(
74                         typing_activity, conversation_reference
75                     )
76 
77                     await context.adapter.send_activities(context, [typing_activity])
78 
79                     start_interval(context, period, period)
80 
81             await timer.set_timeout(aux, delay)
82 
83         def stop_interval():
84             nonlocal finished
85             finished = True
86             timer.set_clear_timer()
87 
88         if context.activity.type == ActivityTypes.message:
89             finished = False
90             await start_interval(context, self._delay, self._period)
91 
92         result = await logic()
93         stop_interval()
94 
95         return result
96
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/libraries/botbuilder-core/botbuilder/core/show_typing_middleware.py b/libraries/botbuilder-core/botbuilder/core/show_typing_middleware.py
--- a/libraries/botbuilder-core/botbuilder/core/show_typing_middleware.py
+++ b/libraries/botbuilder-core/botbuilder/core/show_typing_middleware.py
@@ -1,8 +1,6 @@
 # Copyright (c) Microsoft Corporation. All rights reserved.
 # Licensed under the MIT License.
-
-import time
-from functools import wraps
+import asyncio
 from typing import Awaitable, Callable
 
 from botbuilder.schema import Activity, ActivityTypes
@@ -11,38 +9,38 @@
 from .turn_context import TurnContext
 
 
-def delay(span=0.0):
-    def wrap(func):
-        @wraps(func)
-        async def delayed():
-            time.sleep(span)
-            await func()
-
-        return delayed
-
-    return wrap
-
-
 class Timer:
     clear_timer = False
 
-    async def set_timeout(self, func, time):
-        is_invocation_cancelled = False
-
-        @delay(time)
+    def set_timeout(self, func, span):
         async def some_fn():  # pylint: disable=function-redefined
+            await asyncio.sleep(span)
             if not self.clear_timer:
                 await func()
 
-        await some_fn()
-        return is_invocation_cancelled
+        asyncio.ensure_future(some_fn())
 
     def set_clear_timer(self):
         self.clear_timer = True
 
 
 class ShowTypingMiddleware(Middleware):
+    """
+    When added, this middleware will send typing activities back to the user when a Message activity
+    is received to let them know that the bot has received the message and is working on the response.
+    You can specify a delay before the first typing activity is sent and then a frequency, which
+    determines how often another typing activity is sent. Typing activities will continue to be sent
+    until your bot sends another message back to the user.
+    """
+
     def __init__(self, delay: float = 0.5, period: float = 2.0):
+        """
+        Initializes the middleware.
+
+        :param delay: Delay in seconds for the first typing indicator to be sent.
+        :param period: Delay in seconds for subsequent typing indicators.
+        """
+
         if delay < 0:
             raise ValueError("Delay must be greater than or equal to zero")
 
@@ -55,41 +53,43 @@
     async def on_turn(
         self, context: TurnContext, logic: Callable[[TurnContext], Awaitable]
     ):
-        finished = False
         timer = Timer()
 
-        async def start_interval(context: TurnContext, delay: int, period: int):
+        def start_interval(context: TurnContext, delay, period):
             async def aux():
-                if not finished:
-                    typing_activity = Activity(
-                        type=ActivityTypes.typing,
-                        relates_to=context.activity.relates_to,
-                    )
+                typing_activity = Activity(
+                    type=ActivityTypes.typing, relates_to=context.activity.relates_to,
+                )
 
-                    conversation_reference = TurnContext.get_conversation_reference(
-                        context.activity
-                    )
+                conversation_reference = TurnContext.get_conversation_reference(
+                    context.activity
+                )
 
-                    typing_activity = TurnContext.apply_conversation_reference(
-                        typing_activity, conversation_reference
-                    )
+                typing_activity = TurnContext.apply_conversation_reference(
+                    typing_activity, conversation_reference
+                )
 
-                    await context.adapter.send_activities(context, [typing_activity])
+                asyncio.ensure_future(
+                    context.adapter.send_activities(context, [typing_activity])
+                )
 
-                    start_interval(context, period, period)
+                # restart the timer, with the 'period' value for the delay
+                timer.set_timeout(aux, period)
 
-            await timer.set_timeout(aux, delay)
+            # first time through we use the 'delay' value for the timer.
+            timer.set_timeout(aux, delay)
 
         def stop_interval():
-            nonlocal finished
-            finished = True
             timer.set_clear_timer()
 
+        # if it's a message, start sending typing activities until the
+        # bot logic is done.
         if context.activity.type == ActivityTypes.message:
-            finished = False
-            await start_interval(context, self._delay, self._period)
+            start_interval(context, self._delay, self._period)
 
+        # call the bot logic
         result = await logic()
+
         stop_interval()
 
         return result

{"golden_diff": "diff --git a/libraries/botbuilder-core/botbuilder/core/show_typing_middleware.py b/libraries/botbuilder-core/botbuilder/core/show_typing_middleware.py\n--- a/libraries/botbuilder-core/botbuilder/core/show_typing_middleware.py\n+++ b/libraries/botbuilder-core/botbuilder/core/show_typing_middleware.py\n@@ -1,8 +1,6 @@\n # Copyright (c) Microsoft Corporation. All rights reserved.\r\n # Licensed under the MIT License.\r\n-\r\n-import time\r\n-from functools import wraps\r\n+import asyncio\r\n from typing import Awaitable, Callable\r\n \r\n from botbuilder.schema import Activity, ActivityTypes\r\n@@ -11,38 +9,38 @@\n from .turn_context import TurnContext\r\n \r\n \r\n-def delay(span=0.0):\r\n-    def wrap(func):\r\n-        @wraps(func)\r\n-        async def delayed():\r\n-            time.sleep(span)\r\n-            await func()\r\n-\r\n-        return delayed\r\n-\r\n-    return wrap\r\n-\r\n-\r\n class Timer:\r\n     clear_timer = False\r\n \r\n-    async def set_timeout(self, func, time):\r\n-        is_invocation_cancelled = False\r\n-\r\n-        @delay(time)\r\n+    def set_timeout(self, func, span):\r\n         async def some_fn():  # pylint: disable=function-redefined\r\n+            await asyncio.sleep(span)\r\n             if not self.clear_timer:\r\n                 await func()\r\n \r\n-        await some_fn()\r\n-        return is_invocation_cancelled\r\n+        asyncio.ensure_future(some_fn())\r\n \r\n     def set_clear_timer(self):\r\n         self.clear_timer = True\r\n \r\n \r\n class ShowTypingMiddleware(Middleware):\r\n+    \"\"\"\r\n+    When added, this middleware will send typing activities back to the user when a Message activity\r\n+    is received to let them know that the bot has received the message and is working on the response.\r\n+    You can specify a delay before the first typing activity is sent and then a frequency, which\r\n+    determines how often another typing activity is sent. Typing activities will continue to be sent\r\n+    until your bot sends another message back to the user.\r\n+    \"\"\"\r\n+\r\n     def __init__(self, delay: float = 0.5, period: float = 2.0):\r\n+        \"\"\"\r\n+        Initializes the middleware.\r\n+\r\n+        :param delay: Delay in seconds for the first typing indicator to be sent.\r\n+        :param period: Delay in seconds for subsequent typing indicators.\r\n+        \"\"\"\r\n+\r\n         if delay < 0:\r\n             raise ValueError(\"Delay must be greater than or equal to zero\")\r\n \r\n@@ -55,41 +53,43 @@\n     async def on_turn(\r\n         self, context: TurnContext, logic: Callable[[TurnContext], Awaitable]\r\n     ):\r\n-        finished = False\r\n         timer = Timer()\r\n \r\n-        async def start_interval(context: TurnContext, delay: int, period: int):\r\n+        def start_interval(context: TurnContext, delay, period):\r\n             async def aux():\r\n-                if not finished:\r\n-                    typing_activity = Activity(\r\n-                        type=ActivityTypes.typing,\r\n-                        relates_to=context.activity.relates_to,\r\n-                    )\r\n+                typing_activity = Activity(\r\n+                    type=ActivityTypes.typing, relates_to=context.activity.relates_to,\r\n+                )\r\n \r\n-                    conversation_reference = TurnContext.get_conversation_reference(\r\n-                        context.activity\r\n-                    )\r\n+                conversation_reference = TurnContext.get_conversation_reference(\r\n+                    context.activity\r\n+                )\r\n \r\n-                    typing_activity = TurnContext.apply_conversation_reference(\r\n-                        typing_activity, conversation_reference\r\n-                    )\r\n+                typing_activity = TurnContext.apply_conversation_reference(\r\n+                    typing_activity, conversation_reference\r\n+                )\r\n \r\n-                    await context.adapter.send_activities(context, [typing_activity])\r\n+                asyncio.ensure_future(\r\n+                    context.adapter.send_activities(context, [typing_activity])\r\n+                )\r\n \r\n-                    start_interval(context, period, period)\r\n+                # restart the timer, with the 'period' value for the delay\r\n+                timer.set_timeout(aux, period)\r\n \r\n-            await timer.set_timeout(aux, delay)\r\n+            # first time through we use the 'delay' value for the timer.\r\n+            timer.set_timeout(aux, delay)\r\n \r\n         def stop_interval():\r\n-            nonlocal finished\r\n-            finished = True\r\n             timer.set_clear_timer()\r\n \r\n+        # if it's a message, start sending typing activities until the\r\n+        # bot logic is done.\r\n         if context.activity.type == ActivityTypes.message:\r\n-            finished = False\r\n-            await start_interval(context, self._delay, self._period)\r\n+            start_interval(context, self._delay, self._period)\r\n \r\n+        # call the bot logic\r\n         result = await logic()\r\n+\r\n         stop_interval()\r\n \r\n         return result\n", "issue": "[bug] ShowTypingMiddleware middleware in a python bot not functioning\n## Version\r\n`botbuilder-core        4.7.1`  \r\n`botbuilder-schema      4.7.1`\r\n\r\n## Describe the bug\r\n\r\n\r\n``` python\r\n#app.py \r\nADAPTER = BotFrameworkAdapter(SETTINGS)\r\n# show typing indicator on long activities\r\nADAPTER.use(ShowTypingMiddleware(delay=0.5, period=2.0))\r\n```\r\n\r\n``` python\r\n#bot.py \r\n...\r\n\r\n    async def on_message_activity(self, turn_context: TurnContext):\r\n        if turn_context.activity.text == \"middleware\":\r\n            await asyncio.sleep(10) # mock getting some data \r\n            await turn_context.send_activity(\"done\")\r\n\r\n...\r\n```\r\n\r\n## Expected behavior\r\n\r\nI expect that calling the middleware \r\n- shows a TI for activities taking longer than .5 seconds \r\n- repeat sending a TI to the client every 2 seconds \r\n\r\n## Actual results :  \r\n\r\n - TI is sent one time only\r\n - no repeat TI are sent \r\n - a runtime warning is shown:\r\n```\r\n c:\\develop\\x\\pybot1\\.venv\\lib\\site-packages\\botbuilder\\core\\show_typing_middleware.py:79: \r\nRuntimeWarning: coroutine 'ShowTypingMiddleware.on_turn.<locals>.start_interval' was never awaited\r\n  start_interval(context, period, period)\r\nRuntimeWarning: Enable tracemalloc to get the object allocation traceback\r\n```\r\n\r\nIn the emulator log it is clear that only one TI indicator is sent , and no repeats are to be seen\r\n```\r\n[16:55:12]<- messageYou said 'middleware'\r\n[16:55:12]POST200conversations.:conversationId.activities.:activityId\r\n[16:55:12]POST201directline.conversations.:conversationId.activities\r\n[16:55:43]-> messagemiddleware\r\n[16:55:44]<- typing\r\n[16:55:44]POST200conversations.:conversationId.activities.:activityId\r\n[16:55:54]<- messagedone\r\n[16:55:54]POST200conversations.:conversationId.activities.:activityId\r\n[16:55:54]POST201directline.conversations.:conversationId.activities\r\n```\r\n\r\n## Additional context\r\nalso see Question on [SO](https://stackoverflow.com/posts/60467080/edit)\r\n\n", "before_files": [{"content": "# Copyright (c) Microsoft Corporation. All rights reserved.\r\n# Licensed under the MIT License.\r\n\r\nimport time\r\nfrom functools import wraps\r\nfrom typing import Awaitable, Callable\r\n\r\nfrom botbuilder.schema import Activity, ActivityTypes\r\n\r\nfrom .middleware_set import Middleware\r\nfrom .turn_context import TurnContext\r\n\r\n\r\ndef delay(span=0.0):\r\n    def wrap(func):\r\n        @wraps(func)\r\n        async def delayed():\r\n            time.sleep(span)\r\n            await func()\r\n\r\n        return delayed\r\n\r\n    return wrap\r\n\r\n\r\nclass Timer:\r\n    clear_timer = False\r\n\r\n    async def set_timeout(self, func, time):\r\n        is_invocation_cancelled = False\r\n\r\n        @delay(time)\r\n        async def some_fn():  # pylint: disable=function-redefined\r\n            if not self.clear_timer:\r\n                await func()\r\n\r\n        await some_fn()\r\n        return is_invocation_cancelled\r\n\r\n    def set_clear_timer(self):\r\n        self.clear_timer = True\r\n\r\n\r\nclass ShowTypingMiddleware(Middleware):\r\n    def __init__(self, delay: float = 0.5, period: float = 2.0):\r\n        if delay < 0:\r\n            raise ValueError(\"Delay must be greater than or equal to zero\")\r\n\r\n        if period <= 0:\r\n            raise ValueError(\"Repeat period must be greater than zero\")\r\n\r\n        self._delay = delay\r\n        self._period = period\r\n\r\n    async def on_turn(\r\n        self, context: TurnContext, logic: Callable[[TurnContext], Awaitable]\r\n    ):\r\n        finished = False\r\n        timer = Timer()\r\n\r\n        async def start_interval(context: TurnContext, delay: int, period: int):\r\n            async def aux():\r\n                if not finished:\r\n                    typing_activity = Activity(\r\n                        type=ActivityTypes.typing,\r\n                        relates_to=context.activity.relates_to,\r\n                    )\r\n\r\n                    conversation_reference = TurnContext.get_conversation_reference(\r\n                        context.activity\r\n                    )\r\n\r\n                    typing_activity = TurnContext.apply_conversation_reference(\r\n                        typing_activity, conversation_reference\r\n                    )\r\n\r\n                    await context.adapter.send_activities(context, [typing_activity])\r\n\r\n                    start_interval(context, period, period)\r\n\r\n            await timer.set_timeout(aux, delay)\r\n\r\n        def stop_interval():\r\n            nonlocal finished\r\n            finished = True\r\n            timer.set_clear_timer()\r\n\r\n        if context.activity.type == ActivityTypes.message:\r\n            finished = False\r\n            await start_interval(context, self._delay, self._period)\r\n\r\n        result = await logic()\r\n        stop_interval()\r\n\r\n        return result\r\n", "path": "libraries/botbuilder-core/botbuilder/core/show_typing_middleware.py"}], "after_files": [{"content": "# Copyright (c) Microsoft Corporation. All rights reserved.\r\n# Licensed under the MIT License.\r\nimport asyncio\r\nfrom typing import Awaitable, Callable\r\n\r\nfrom botbuilder.schema import Activity, ActivityTypes\r\n\r\nfrom .middleware_set import Middleware\r\nfrom .turn_context import TurnContext\r\n\r\n\r\nclass Timer:\r\n    clear_timer = False\r\n\r\n    def set_timeout(self, func, span):\r\n        async def some_fn():  # pylint: disable=function-redefined\r\n            await asyncio.sleep(span)\r\n            if not self.clear_timer:\r\n                await func()\r\n\r\n        asyncio.ensure_future(some_fn())\r\n\r\n    def set_clear_timer(self):\r\n        self.clear_timer = True\r\n\r\n\r\nclass ShowTypingMiddleware(Middleware):\r\n    \"\"\"\r\n    When added, this middleware will send typing activities back to the user when a Message activity\r\n    is received to let them know that the bot has received the message and is working on the response.\r\n    You can specify a delay before the first typing activity is sent and then a frequency, which\r\n    determines how often another typing activity is sent. Typing activities will continue to be sent\r\n    until your bot sends another message back to the user.\r\n    \"\"\"\r\n\r\n    def __init__(self, delay: float = 0.5, period: float = 2.0):\r\n        \"\"\"\r\n        Initializes the middleware.\r\n\r\n        :param delay: Delay in seconds for the first typing indicator to be sent.\r\n        :param period: Delay in seconds for subsequent typing indicators.\r\n        \"\"\"\r\n\r\n        if delay < 0:\r\n            raise ValueError(\"Delay must be greater than or equal to zero\")\r\n\r\n        if period <= 0:\r\n            raise ValueError(\"Repeat period must be greater than zero\")\r\n\r\n        self._delay = delay\r\n        self._period = period\r\n\r\n    async def on_turn(\r\n        self, context: TurnContext, logic: Callable[[TurnContext], Awaitable]\r\n    ):\r\n        timer = Timer()\r\n\r\n        def start_interval(context: TurnContext, delay, period):\r\n            async def aux():\r\n                typing_activity = Activity(\r\n                    type=ActivityTypes.typing, relates_to=context.activity.relates_to,\r\n                )\r\n\r\n                conversation_reference = TurnContext.get_conversation_reference(\r\n                    context.activity\r\n                )\r\n\r\n                typing_activity = TurnContext.apply_conversation_reference(\r\n                    typing_activity, conversation_reference\r\n                )\r\n\r\n                asyncio.ensure_future(\r\n                    context.adapter.send_activities(context, [typing_activity])\r\n                )\r\n\r\n                # restart the timer, with the 'period' value for the delay\r\n                timer.set_timeout(aux, period)\r\n\r\n            # first time through we use the 'delay' value for the timer.\r\n            timer.set_timeout(aux, delay)\r\n\r\n        def stop_interval():\r\n            timer.set_clear_timer()\r\n\r\n        # if it's a message, start sending typing activities until the\r\n        # bot logic is done.\r\n        if context.activity.type == ActivityTypes.message:\r\n            start_interval(context, self._delay, self._period)\r\n\r\n        # call the bot logic\r\n        result = await logic()\r\n\r\n        stop_interval()\r\n\r\n        return result\r\n", "path": "libraries/botbuilder-core/botbuilder/core/show_typing_middleware.py"}]}