docs: def parse(self, m, prefix=None):
          """Parse branch notification messages sent by Launchpad.
          """
  
          subject = m["subject"]
          match = re.search(r"^\s*\[Branch\s+([^]]+)\]", subject)
          if match:
              repository = match.group(1)
          else:
              repository = None
  
          # Put these into a dictionary, otherwise we cannot assign them
          # from nested function definitions.
          d = {'files': [], 'comments': ""}
          gobbler = None
          rev = None
          author = None
          when = util.now()
  
          def gobble_comment(s):
              d['comments'] += s + "\n"
  
          def gobble_removed(s):
              d['files'].append('%s REMOVED' % s)
  
          def gobble_added(s):
              d['files'].append('%s ADDED' % s)
  
          def gobble_modified(s):
              d['files'].append('%s MODIFIED' % s)
  
          def gobble_renamed(s):
              match = re.search(r"^(.+) => (.+)$", s)
              if match:
                  d['files'].append('%s RENAMED %s' %
                                    (match.group(1), match.group(2)))
              else:
                  d['files'].append('%s RENAMED' % s)
  
          lines = list(body_line_iterator(m, True))
          rev = None
          while lines:
              line = str(lines.pop(0), "utf-8", errors="ignore")
  
              # revno: 101
              match = re.search(r"^revno: ([0-9.]+)", line)
              if match:
                  rev = match.group(1)
  
              # committer: Joe <joe@acme.com>
              match = re.search(r"^committer: (.*)$", line)
              if match:
                  author = match.group(1)
  
              # timestamp: Fri 2009-05-15 10:35:43 +0200
              # datetime.strptime() is supposed to support %z for time zone, but
              # it does not seem to work. So handle the time zone manually.
              match = re.search(
                  r"^timestamp: [a-zA-Z]{3} (\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}) ([-+])(\d{2})(\d{2})$", line)
              if match:
                  datestr = match.group(1)
                  tz_sign = match.group(2)
                  tz_hours = match.group(3)
                  tz_minutes = match.group(4)
                  when = parseLaunchpadDate(
                      datestr, tz_sign, tz_hours, tz_minutes)
  
              if re.search(r"^message:\s*$", line):
                  gobbler = gobble_comment
              elif re.search(r"^removed:\s*$", line):
                  gobbler = gobble_removed
              elif re.search(r"^added:\s*$", line):
                  gobbler = gobble_added
              elif re.search(r"^renamed:\s*$", line):
                  gobbler = gobble_renamed
              elif re.search(r"^modified:\s*$", line):
                  gobbler = gobble_modified
              elif re.search(r"^  ", line) and gobbler:
                  gobbler(line[2:-1])  # Use :-1 to gobble trailing newline
  
          # Determine the name of the branch.
          branch = None
          if self.branchMap and repository:
              if repository in self.branchMap:
                  branch = self.branchMap[repository]
              elif ("lp:" + repository) in self.branchMap:
                  branch = self.branchMap['lp:' + repository]
          if not branch:
              if self.defaultBranch:
                  branch = self.defaultBranch
              else:
                  if repository:
                      branch = 'lp:' + repository
                  else:
                      branch = None
  
          if rev and author:
              return ('bzr', dict(author=author, files=d['files'],
                                  comments=d['comments'],
                                  when=when, revision=rev,
                                  branch=branch, repository=repository or ''))
          return None