public function receiveMessage(PhabricatorIRCMessage $message)
 {
     switch ($message->getCommand()) {
         case 'PRIVMSG':
             $channel = $message->getChannel();
             if (!$channel) {
                 break;
             }
             $message = $message->getMessageText();
             $matches = null;
             $phids = array();
             $pattern = '@' . '(?<!/)(?:^|\\b)' . '(D|T|P|V)(\\d+)' . '(?:\\b|$)' . '@';
             $revision_ids = array();
             $task_ids = array();
             $paste_ids = array();
             $commit_names = array();
             $vote_ids = array();
             if (preg_match_all($pattern, $message, $matches, PREG_SET_ORDER)) {
                 foreach ($matches as $match) {
                     switch ($match[1]) {
                         case 'D':
                             $revision_ids[] = $match[2];
                             break;
                         case 'T':
                             $task_ids[] = $match[2];
                             break;
                         case 'P':
                             $paste_ids[] = $match[2];
                             break;
                         case 'V':
                             $vote_ids[] = $match[2];
                             break;
                     }
                 }
             }
             $pattern = '@' . '(?<!/)(?:^|\\b)' . '(r[A-Z]+[0-9a-z]{1,40})' . '(?:\\b|$)' . '@';
             if (preg_match_all($pattern, $message, $matches, PREG_SET_ORDER)) {
                 foreach ($matches as $match) {
                     $commit_names[] = $match[1];
                 }
             }
             $output = array();
             if ($revision_ids) {
                 $revisions = $this->getConduit()->callMethodSynchronous('differential.find', array('query' => 'revision-ids', 'guids' => $revision_ids));
                 foreach ($revisions as $revision) {
                     $output[$revision['phid']] = 'D' . $revision['id'] . ' ' . $revision['name'] . ' - ' . $revision['uri'];
                 }
             }
             if ($task_ids) {
                 foreach ($task_ids as $task_id) {
                     $task = $this->getConduit()->callMethodSynchronous('maniphest.info', array('task_id' => $task_id));
                     $output[$task['phid']] = 'T' . $task['id'] . ': ' . $task['title'] . ' (Priority: ' . $task['priority'] . ') - ' . $task['uri'];
                 }
             }
             if ($vote_ids) {
                 foreach ($vote_ids as $vote_id) {
                     $vote = $this->getConduit()->callMethodSynchronous('slowvote.info', array('poll_id' => $vote_id));
                     $output[$vote['phid']] = 'V' . $vote['id'] . ': ' . $vote['question'] . ' Come Vote ' . $vote['uri'];
                 }
             }
             if ($paste_ids) {
                 foreach ($paste_ids as $paste_id) {
                     $paste = $this->getConduit()->callMethodSynchronous('paste.info', array('paste_id' => $paste_id));
                     // Eventually I'd like to show the username of the paster as well,
                     // however that will need something like a user.username_from_phid
                     // since we (ideally) want to keep the bot to Conduit calls...and
                     // not call to Phabricator-specific stuff (like actually loading
                     // the User object and fetching his/her username.)
                     $output[$paste['phid']] = 'P' . $paste['id'] . ': ' . $paste['uri'] . ' - ' . $paste['title'];
                     if ($paste['language']) {
                         $output[$paste['phid']] .= ' (' . $paste['language'] . ')';
                     }
                 }
             }
             if ($commit_names) {
                 $commits = $this->getConduit()->callMethodSynchronous('diffusion.getcommits', array('commits' => $commit_names));
                 foreach ($commits as $commit) {
                     if (isset($commit['error'])) {
                         continue;
                     }
                     $output[$commit['commitPHID']] = $commit['uri'];
                 }
             }
             foreach ($output as $phid => $description) {
                 // Don't mention the same object more than once every 10 minutes, so
                 // we avoid spamming the chat over and over again for discsussions of
                 // a specific revision, for example.
                 $quiet_until = idx($this->recentlyMentioned, $phid, 0) + 60 * 10;
                 if (time() < $quiet_until) {
                     continue;
                 }
                 $this->recentlyMentioned[$phid] = time();
                 $this->write('PRIVMSG', "{$channel} :{$description}");
             }
             break;
     }
 }
 private function handleSymbols(PhabricatorIRCMessage $message)
 {
     $channel = $message->getChannel();
     $text = $message->getMessageText();
     $matches = null;
     if (!preg_match('/where is (\\S+?)\\?/i', $text, $matches)) {
         return;
     }
     $symbol = $matches[1];
     $results = $this->getConduit()->callMethodSynchronous('diffusion.findsymbols', array('name' => $symbol));
     if (count($results) > 1) {
         $uri = $this->getURI('/diffusion/symbol/' . $symbol . '/');
         $response = "Multiple symbols named '{$symbol}': {$uri}";
     } else {
         if (count($results) == 1) {
             $result = head($results);
             $response = $result['type'] . ' ' . $result['name'] . ' ' . '(' . $result['language'] . '): ' . $result['uri'];
         } else {
             $response = "No symbol '{$symbol}' found anywhere.";
         }
     }
     $this->write('PRIVMSG', "{$channel} :{$response}");
 }