Implement Bugtraq as a standalone parse step

Summary:
Ref T3840. I wasn't able to figure the bug in this logic out initially and it doesn't //really// belong on PhabricatorRepository. Separate it out and write tests for it.

The current logic lives here:

https://secure.phabricator.com/diffusion/P/browse/master/src/applications/repository/storage/PhabricatorRepository.php;d3de57716a4fc528$695-744

The bug was that the logic basically does this:

  foreach (capturing match) {
    foreach (array_reverse(selection match)) {
      substr_replace(...);
    }
  }

So we do the selection matches in reverse order (which avoids disrupting the offset), but the capturing matches in forward order. So if you have text like this:

  Issues: 123
  Issues: 345

...everything will end up garbled. Instead, collect all replacements and then do them all in reverse order.

The next diff will replace the logic in Phabricator with a call to this logic.

Test Plan: Unit tests.

Reviewers: btrahan, vrana

Reviewed By: btrahan

CC: aran

Maniphest Tasks: T3840

Differential Revision: https://secure.phabricator.com/D7021