prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Duplicated shell prompt 
  # Description
  When I run the hello skill from the shell, I found duplicated shell prompt output. I think there's some issue with the shell connector. 
  
  
  ## Steps to Reproduce
  ```
  qidong@ubuntu:~/Documents/opsdroid$ opsdroid start
  mybot> hello
  Hello qidong
  mybot> mybot>
  ```
  
  
  ## Expected Functionality
  There should be only one prompt printed after the skill response. 
  
  ## Experienced Functionality
  One extra prompt is printed. 
  
  
  ## Configuration File
  
  ```yaml
  logging:
    console: false
  
  connectors:
    websocket:
      bot-name: "mybot"
      max-connections: 10
      connection-timeout: 10
    
    shell:
      bot-name: "mybot"
  
  skills:
    ## Hello (https://github.com/opsdroid/skill-hello)
    hello: {}
  ```
  
  
  
  
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `opsdroid/connector/shell/__init__.py`
  Content:
  ```
  1 """A connector to send messages using the command line."""
  2 import logging
  3 import os
  4 import sys
  5 import platform
  6 import asyncio
  7 
  8 from opsdroid.connector import Connector, register_event
  9 from opsdroid.events import Message
  10 
  11 _LOGGER = logging.getLogger(__name__)
  12 CONFIG_SCHEMA = {"bot-name": str}
  13 
  14 
  15 class ConnectorShell(Connector):
  16     """A connector to send messages using the command line."""
  17 
  18     def __init__(self, config, opsdroid=None):
  19         """Create the connector."""
  20         _LOGGER.debug(_("Loaded shell Connector."))
  21         super().__init__(config, opsdroid=opsdroid)
  22         self.name = "shell"
  23         self.config = config
  24         self.bot_name = config.get("bot-name", "opsdroid")
  25         self.prompt_length = None
  26         self.listening = True
  27         self.reader = None
  28         self._closing = asyncio.Event()
  29         self.loop = asyncio.get_event_loop()
  30 
  31         for name in ("LOGNAME", "USER", "LNAME", "USERNAME"):
  32             user = os.environ.get(name)
  33             if user:
  34                 self.user = user
  35 
  36     @property
  37     def is_listening(self):
  38         """Get listening status."""
  39         return self.listening
  40 
  41     @is_listening.setter
  42     def is_listening(self, val):
  43         """Set listening status."""
  44         self.listening = val
  45 
  46     async def read_stdin(self):
  47         """Create a stream reader to read stdin asynchronously.
  48 
  49         Returns:
  50             class: asyncio.streams.StreamReader
  51 
  52         """
  53         self.reader = asyncio.StreamReader(loop=self.loop)
  54         reader_protocol = asyncio.StreamReaderProtocol(self.reader)
  55 
  56         await self.loop.connect_read_pipe(lambda: reader_protocol, sys.stdin)
  57 
  58         return self.reader
  59 
  60     async def async_input(self):
  61         """Read user input asynchronously from stdin.
  62 
  63         Returns:
  64             string: A decoded string from user input.
  65 
  66         """
  67         if not self.reader:
  68             self.reader = await self.read_stdin()
  69         line = await self.reader.readline()
  70 
  71         return line.decode("utf8").replace("\r", "").replace("\n", "")
  72 
  73     def draw_prompt(self):
  74         """Draw the user input prompt."""
  75         prompt = self.bot_name + "> "
  76         self.prompt_length = len(prompt)
  77         print(prompt, end="", flush=True)
  78 
  79     def clear_prompt(self):
  80         """Clear the prompt."""
  81         print("\r" + (" " * self.prompt_length) + "\r", end="", flush=True)
  82 
  83     async def parseloop(self):
  84         """Parseloop moved out for testing."""
  85         self.draw_prompt()
  86         user_input = await self.async_input()
  87         message = Message(text=user_input, user=self.user, target=None, connector=self)
  88         await self.opsdroid.parse(message)
  89 
  90     async def _parse_message(self):
  91         """Parse user input."""
  92         while self.is_listening:
  93             await self.parseloop()
  94 
  95     async def connect(self):
  96         """Connect to the shell.
  97 
  98         There is nothing to do here since stdin is already available.
  99 
  100         Since this is the first method called when opsdroid starts, a logging
  101         message is shown if the user is using windows.
  102 
  103         """
  104         if platform.system() == "Windows":
  105             _LOGGER.warning(
  106                 "The shell connector does not work on windows. Please install the Opsdroid Desktop App."
  107             )
  108         pass
  109 
  110     async def listen(self):
  111         """Listen for and parse new user input."""
  112         _LOGGER.debug(_("Connecting to shell."))
  113         message_processor = self.loop.create_task(self._parse_message())
  114         await self._closing.wait()
  115         message_processor.cancel()
  116 
  117     @register_event(Message)
  118     async def respond(self, message):
  119         """Respond with a message.
  120 
  121         Args:
  122             message (object): An instance of Message
  123 
  124         """
  125         _LOGGER.debug(_("Responding with: %s."), message.text)
  126         self.clear_prompt()
  127         print(message.text)
  128         self.draw_prompt()
  129 
  130     async def disconnect(self):
  131         """Disconnects the connector."""
  132         self._closing.set()
  133
  ```
  --- 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()
  
  ```
  
golden_diff: diff --git a/opsdroid/connector/shell/__init__.py b/opsdroid/connector/shell/__init__.py
  --- a/opsdroid/connector/shell/__init__.py
  +++ b/opsdroid/connector/shell/__init__.py
  @@ -125,7 +125,6 @@
           _LOGGER.debug(_("Responding with: %s."), message.text)
           self.clear_prompt()
           print(message.text)
  -        self.draw_prompt()
   
       async def disconnect(self):
           """Disconnects the connector."""
  
verification_info: {"golden_diff": "diff --git a/opsdroid/connector/shell/__init__.py b/opsdroid/connector/shell/__init__.py\n--- a/opsdroid/connector/shell/__init__.py\n+++ b/opsdroid/connector/shell/__init__.py\n@@ -125,7 +125,6 @@\n         _LOGGER.debug(_(\"Responding with: %s.\"), message.text)\n         self.clear_prompt()\n         print(message.text)\n-        self.draw_prompt()\n \n     async def disconnect(self):\n         \"\"\"Disconnects the connector.\"\"\"\n", "issue": "Duplicated shell prompt \n# Description\r\nWhen I run the hello skill from the shell, I found duplicated shell prompt output. I think there's some issue with the shell connector. \r\n\r\n\r\n## Steps to Reproduce\r\n```\r\nqidong@ubuntu:~/Documents/opsdroid$ opsdroid start\r\nmybot> hello\r\nHello qidong\r\nmybot> mybot>\r\n```\r\n\r\n\r\n## Expected Functionality\r\nThere should be only one prompt printed after the skill response. \r\n\r\n## Experienced Functionality\r\nOne extra prompt is printed. \r\n\r\n\r\n## Configuration File\r\n\r\n```yaml\r\nlogging:\r\n  console: false\r\n\r\nconnectors:\r\n  websocket:\r\n    bot-name: \"mybot\"\r\n    max-connections: 10\r\n    connection-timeout: 10\r\n  \r\n  shell:\r\n    bot-name: \"mybot\"\r\n\r\nskills:\r\n  ## Hello (https://github.com/opsdroid/skill-hello)\r\n  hello: {}\r\n```\r\n\r\n\r\n\r\n\n", "before_files": [{"content": "\"\"\"A connector to send messages using the command line.\"\"\"\nimport logging\nimport os\nimport sys\nimport platform\nimport asyncio\n\nfrom opsdroid.connector import Connector, register_event\nfrom opsdroid.events import Message\n\n_LOGGER = logging.getLogger(__name__)\nCONFIG_SCHEMA = {\"bot-name\": str}\n\n\nclass ConnectorShell(Connector):\n    \"\"\"A connector to send messages using the command line.\"\"\"\n\n    def __init__(self, config, opsdroid=None):\n        \"\"\"Create the connector.\"\"\"\n        _LOGGER.debug(_(\"Loaded shell Connector.\"))\n        super().__init__(config, opsdroid=opsdroid)\n        self.name = \"shell\"\n        self.config = config\n        self.bot_name = config.get(\"bot-name\", \"opsdroid\")\n        self.prompt_length = None\n        self.listening = True\n        self.reader = None\n        self._closing = asyncio.Event()\n        self.loop = asyncio.get_event_loop()\n\n        for name in (\"LOGNAME\", \"USER\", \"LNAME\", \"USERNAME\"):\n            user = os.environ.get(name)\n            if user:\n                self.user = user\n\n    @property\n    def is_listening(self):\n        \"\"\"Get listening status.\"\"\"\n        return self.listening\n\n    @is_listening.setter\n    def is_listening(self, val):\n        \"\"\"Set listening status.\"\"\"\n        self.listening = val\n\n    async def read_stdin(self):\n        \"\"\"Create a stream reader to read stdin asynchronously.\n\n        Returns:\n            class: asyncio.streams.StreamReader\n\n        \"\"\"\n        self.reader = asyncio.StreamReader(loop=self.loop)\n        reader_protocol = asyncio.StreamReaderProtocol(self.reader)\n\n        await self.loop.connect_read_pipe(lambda: reader_protocol, sys.stdin)\n\n        return self.reader\n\n    async def async_input(self):\n        \"\"\"Read user input asynchronously from stdin.\n\n        Returns:\n            string: A decoded string from user input.\n\n        \"\"\"\n        if not self.reader:\n            self.reader = await self.read_stdin()\n        line = await self.reader.readline()\n\n        return line.decode(\"utf8\").replace(\"\\r\", \"\").replace(\"\\n\", \"\")\n\n    def draw_prompt(self):\n        \"\"\"Draw the user input prompt.\"\"\"\n        prompt = self.bot_name + \"> \"\n        self.prompt_length = len(prompt)\n        print(prompt, end=\"\", flush=True)\n\n    def clear_prompt(self):\n        \"\"\"Clear the prompt.\"\"\"\n        print(\"\\r\" + (\" \" * self.prompt_length) + \"\\r\", end=\"\", flush=True)\n\n    async def parseloop(self):\n        \"\"\"Parseloop moved out for testing.\"\"\"\n        self.draw_prompt()\n        user_input = await self.async_input()\n        message = Message(text=user_input, user=self.user, target=None, connector=self)\n        await self.opsdroid.parse(message)\n\n    async def _parse_message(self):\n        \"\"\"Parse user input.\"\"\"\n        while self.is_listening:\n            await self.parseloop()\n\n    async def connect(self):\n        \"\"\"Connect to the shell.\n\n        There is nothing to do here since stdin is already available.\n\n        Since this is the first method called when opsdroid starts, a logging\n        message is shown if the user is using windows.\n\n        \"\"\"\n        if platform.system() == \"Windows\":\n            _LOGGER.warning(\n                \"The shell connector does not work on windows. Please install the Opsdroid Desktop App.\"\n            )\n        pass\n\n    async def listen(self):\n        \"\"\"Listen for and parse new user input.\"\"\"\n        _LOGGER.debug(_(\"Connecting to shell.\"))\n        message_processor = self.loop.create_task(self._parse_message())\n        await self._closing.wait()\n        message_processor.cancel()\n\n    @register_event(Message)\n    async def respond(self, message):\n        \"\"\"Respond with a message.\n\n        Args:\n            message (object): An instance of Message\n\n        \"\"\"\n        _LOGGER.debug(_(\"Responding with: %s.\"), message.text)\n        self.clear_prompt()\n        print(message.text)\n        self.draw_prompt()\n\n    async def disconnect(self):\n        \"\"\"Disconnects the connector.\"\"\"\n        self._closing.set()\n", "path": "opsdroid/connector/shell/__init__.py"}], "after_files": [{"content": "\"\"\"A connector to send messages using the command line.\"\"\"\nimport logging\nimport os\nimport sys\nimport platform\nimport asyncio\n\nfrom opsdroid.connector import Connector, register_event\nfrom opsdroid.events import Message\n\n_LOGGER = logging.getLogger(__name__)\nCONFIG_SCHEMA = {\"bot-name\": str}\n\n\nclass ConnectorShell(Connector):\n    \"\"\"A connector to send messages using the command line.\"\"\"\n\n    def __init__(self, config, opsdroid=None):\n        \"\"\"Create the connector.\"\"\"\n        _LOGGER.debug(_(\"Loaded shell Connector.\"))\n        super().__init__(config, opsdroid=opsdroid)\n        self.name = \"shell\"\n        self.config = config\n        self.bot_name = config.get(\"bot-name\", \"opsdroid\")\n        self.prompt_length = None\n        self.listening = True\n        self.reader = None\n        self._closing = asyncio.Event()\n        self.loop = asyncio.get_event_loop()\n\n        for name in (\"LOGNAME\", \"USER\", \"LNAME\", \"USERNAME\"):\n            user = os.environ.get(name)\n            if user:\n                self.user = user\n\n    @property\n    def is_listening(self):\n        \"\"\"Get listening status.\"\"\"\n        return self.listening\n\n    @is_listening.setter\n    def is_listening(self, val):\n        \"\"\"Set listening status.\"\"\"\n        self.listening = val\n\n    async def read_stdin(self):\n        \"\"\"Create a stream reader to read stdin asynchronously.\n\n        Returns:\n            class: asyncio.streams.StreamReader\n\n        \"\"\"\n        self.reader = asyncio.StreamReader(loop=self.loop)\n        reader_protocol = asyncio.StreamReaderProtocol(self.reader)\n\n        await self.loop.connect_read_pipe(lambda: reader_protocol, sys.stdin)\n\n        return self.reader\n\n    async def async_input(self):\n        \"\"\"Read user input asynchronously from stdin.\n\n        Returns:\n            string: A decoded string from user input.\n\n        \"\"\"\n        if not self.reader:\n            self.reader = await self.read_stdin()\n        line = await self.reader.readline()\n\n        return line.decode(\"utf8\").replace(\"\\r\", \"\").replace(\"\\n\", \"\")\n\n    def draw_prompt(self):\n        \"\"\"Draw the user input prompt.\"\"\"\n        prompt = self.bot_name + \"> \"\n        self.prompt_length = len(prompt)\n        print(prompt, end=\"\", flush=True)\n\n    def clear_prompt(self):\n        \"\"\"Clear the prompt.\"\"\"\n        print(\"\\r\" + (\" \" * self.prompt_length) + \"\\r\", end=\"\", flush=True)\n\n    async def parseloop(self):\n        \"\"\"Parseloop moved out for testing.\"\"\"\n        self.draw_prompt()\n        user_input = await self.async_input()\n        message = Message(text=user_input, user=self.user, target=None, connector=self)\n        await self.opsdroid.parse(message)\n\n    async def _parse_message(self):\n        \"\"\"Parse user input.\"\"\"\n        while self.is_listening:\n            await self.parseloop()\n\n    async def connect(self):\n        \"\"\"Connect to the shell.\n\n        There is nothing to do here since stdin is already available.\n\n        Since this is the first method called when opsdroid starts, a logging\n        message is shown if the user is using windows.\n\n        \"\"\"\n        if platform.system() == \"Windows\":\n            _LOGGER.warning(\n                \"The shell connector does not work on windows. Please install the Opsdroid Desktop App.\"\n            )\n        pass\n\n    async def listen(self):\n        \"\"\"Listen for and parse new user input.\"\"\"\n        _LOGGER.debug(_(\"Connecting to shell.\"))\n        message_processor = self.loop.create_task(self._parse_message())\n        await self._closing.wait()\n        message_processor.cancel()\n\n    @register_event(Message)\n    async def respond(self, message):\n        \"\"\"Respond with a message.\n\n        Args:\n            message (object): An instance of Message\n\n        \"\"\"\n        _LOGGER.debug(_(\"Responding with: %s.\"), message.text)\n        self.clear_prompt()\n        print(message.text)\n\n    async def disconnect(self):\n        \"\"\"Disconnects the connector.\"\"\"\n        self._closing.set()\n", "path": "opsdroid/connector/shell/__init__.py"}]}