docs: def run(self):
          ''' run all patterns in the playbook '''
          plays = []
          matched_tags_all = set()
          unmatched_tags_all = set()
  
          # loop through all patterns and run them
          self.callbacks.on_start()
          for (play_ds, play_basedir) in zip(self.playbook, self.play_basedirs):
              play = Play(self, play_ds, play_basedir)
              matched_tags, unmatched_tags = play.compare_tags(self.only_tags)
              matched_tags_all = matched_tags_all | matched_tags
              unmatched_tags_all = unmatched_tags_all | unmatched_tags
  
              # if we have matched_tags, the play must be run.
              # if the play contains no tasks, assume we just want to gather facts
              if (len(matched_tags) > 0 or len(play.tasks()) == 0):
                  plays.append(play)
  
          # if the playbook is invoked with --tags that don't exist at all in the playbooks
          # then we need to raise an error so that the user can correct the arguments.
          unknown_tags = set(self.only_tags) - (matched_tags_all | unmatched_tags_all)
          unknown_tags.discard('all')
  
          if len(unknown_tags) > 0:
              unmatched_tags_all.discard('all')
              msg = 'tag(s) not found in playbook: %s.  possible values: %s'
              unknown = ','.join(sorted(unknown_tags))
              unmatched = ','.join(sorted(unmatched_tags_all))
              raise errors.AnsibleError(msg % (unknown, unmatched))
  
          for play in plays:
              if not self._run_play(play):
                  break
  
          # summarize the results
          results = {}
          for host in self.stats.processed.keys():
              results[host] = self.stats.summarize(host)
          return results