docs: async def run(self):
          """Main loop of the TelegramClient, will wait for user action"""
  
          # Once everything is ready, we can add an event handler.
          #
          # Events are an abstraction over Telegram's "Updates" and
          # are much easier to use.
          self.add_event_handler(self.message_handler, events.NewMessage)
  
          # Enter a while loop to chat as long as the user wants
          while True:
              # Retrieve the top dialogs. You can set the limit to None to
              # retrieve all of them if you wish, but beware that may take
              # a long time if you have hundreds of them.
              dialog_count = 15
  
              # Entities represent the user, chat or channel
              # corresponding to the dialog on the same index.
              dialogs = await self.get_dialogs(limit=dialog_count)
  
              i = None
              while i is None:
                  print_title('Dialogs window')
  
                  # Display them so the user can choose
                  for i, dialog in enumerate(dialogs, start=1):
                      sprint('{}. {}'.format(i, get_display_name(dialog.entity)))
  
                  # Let the user decide who they want to talk to
                  print()
                  print('> Who do you want to send messages to?')
                  print('> Available commands:')
                  print('  !q: Quits the dialogs window and exits.')
                  print('  !l: Logs out, terminating this session.')
                  print()
                  i = await async_input('Enter dialog ID or a command: ')
                  if i == '!q':
                      return
                  if i == '!l':
                      # Logging out will cause the user to need to reenter the
                      # code next time they want to use the library, and will
                      # also delete the *.session file off the filesystem.
                      #
                      # This is not the same as simply calling .disconnect(),
                      # which simply shuts down everything gracefully.
                      await self.log_out()
                      return
  
                  try:
                      i = int(i if i else 0) - 1
                      # Ensure it is inside the bounds, otherwise retry
                      if not 0 <= i < dialog_count:
                          i = None
                  except ValueError:
                      i = None
  
              # Retrieve the selected user (or chat, or channel)
              entity = dialogs[i].entity
  
              # Show some information
              print_title('Chat with "{}"'.format(get_display_name(entity)))
              print('Available commands:')
              print('  !q:  Quits the current chat.')
              print('  !Q:  Quits the current chat and exits.')
              print('  !h:  prints the latest messages (message History).')
              print('  !up  <path>: Uploads and sends the Photo from path.')
              print('  !uf  <path>: Uploads and sends the File from path.')
              print('  !d   <msg-id>: Deletes a message by its id')
              print('  !dm  <msg-id>: Downloads the given message Media (if any).')
              print('  !dp: Downloads the current dialog Profile picture.')
              print('  !i:  Prints information about this chat..')
              print()
  
              # And start a while loop to chat
              while True:
                  msg = await async_input('Enter a message: ')
                  # Quit
                  if msg == '!q':
                      break
                  elif msg == '!Q':
                      return
  
                  # History
                  elif msg == '!h':
                      # First retrieve the messages and some information
                      messages = await self.get_messages(entity, limit=10)
  
                      # Iterate over all (in reverse order so the latest appear
                      # the last in the console) and print them with format:
                      # "[hh:mm] Sender: Message"
                      for msg in reversed(messages):
                          # Note how we access .sender here. Since we made an
                          # API call using the self client, it will always have
                          # information about the sender. This is different to
                          # events, where Telegram may not always send the user.
                          name = get_display_name(msg.sender)
  
                          # Format the message content
                          if getattr(msg, 'media', None):
                              self.found_media[msg.id] = msg
                              content = '<{}> {}'.format(
                                  type(msg.media).__name__, msg.message)
  
                          elif hasattr(msg, 'message'):
                              content = msg.message
                          elif hasattr(msg, 'action'):
                              content = str(msg.action)
                          else:
                              # Unknown message, simply print its class name
                              content = type(msg).__name__
  
                          # And print it to the user
                          sprint('[{}:{}] (ID={}) {}: {}'.format(
                              msg.date.hour, msg.date.minute, msg.id, name, content))
  
                  # Send photo
                  elif msg.startswith('!up '):
                      # Slice the message to get the path
                      path = msg[len('!up '):]
                      await self.send_photo(path=path, entity=entity)
  
                  # Send file (document)
                  elif msg.startswith('!uf '):
                      # Slice the message to get the path
                      path = msg[len('!uf '):]
                      await self.send_document(path=path, entity=entity)
  
                  # Delete messages
                  elif msg.startswith('!d '):
                      # Slice the message to get message ID
                      msg = msg[len('!d '):]
                      deleted_msg = await self.delete_messages(entity, msg)
                      print('Deleted {}'.format(deleted_msg))
  
                  # Download media
                  elif msg.startswith('!dm '):
                      # Slice the message to get message ID
                      await self.download_media_by_id(msg[len('!dm '):])
  
                  # Download profile photo
                  elif msg == '!dp':
                      print('Downloading profile picture to usermedia/...')
                      os.makedirs('usermedia', exist_ok=True)
                      output = await self.download_profile_photo(entity,
                                                                 'usermedia')
                      if output:
                          print('Profile picture downloaded to', output)
                      else:
                          print('No profile picture found for this user!')
  
                  elif msg == '!i':
                      attributes = list(entity.to_dict().items())
                      pad = max(len(x) for x, _ in attributes)
                      for name, val in attributes:
                          print("{:<{width}} : {}".format(name, val, width=pad))
  
                  # Send chat message (if any)
                  elif msg:
                      await self.send_message(entity, msg, link_preview=False)