Esempio n. 1
0
 private function execute(CommandMessage $command) : \Generator
 {
     if (!(yield $command->getRoom()->isApproved())) {
         return;
     }
     return $this->chatClient->postReply($command, sprintf('I have been running for %s, since %s', dateinterval_to_string((new \DateTime())->diff($this->startTime)), $this->startTime->format('Y-m-d H:i:s')));
 }
Esempio n. 2
0
 public function scrabble(Command $command) : Promise
 {
     if ($command->hasParameters() === false) {
         return $this->chatClient->postMessage($command->getRoom(), self::USAGE);
     }
     return $this->chatClient->postReply($command, $this->formatScores($this->calculateScores($this->getScorableWords($command->getParameters()))));
 }
Esempio n. 3
0
 private function getPostBody(Command $command) : string
 {
     $parameters = $command->getParameters();
     if (count($parameters) < 2) {
         throw new \RuntimeException('Usage: `!!post [options] postdata url`');
     }
     return $parameters[count($parameters) - 2];
 }
Esempio n. 4
0
 public function search(Command $command) : \Generator
 {
     if (!$command->hasParameters()) {
         return new Success();
     }
     $response = (yield $this->httpClient->request('http://www.imdb.com/xml/find?xml=1&nr=1&tt=on&q=' . rawurlencode(implode(' ', $command->getParameters()))));
     return $this->chatClient->postMessage($command->getRoom(), $this->getMessage($response));
 }
Esempio n. 5
0
 public function questionify(CommandMessage $command)
 {
     $text = (yield $this->messageResolver->resolveMessageText($command->getRoom(), $command->getText()));
     if (preg_match('/\\?\\s*$/', $text)) {
         return $this->chatClient->postReply($command, 'That\'s already a question');
     }
     return $this->chatClient->postMessage($command->getRoom(), rtrim($text) . '?');
 }
Esempio n. 6
0
 public function lmgtfy(Command $command)
 {
     $text = $command->getText();
     if ((bool) preg_match('~^http://chat\\.stackoverflow\\.com/transcript/message/(\\d+)(#\\d+)?$~', $text)) {
         $text = (yield $this->messageResolver->resolveMessageText($command->getRoom(), $text));
     }
     return $this->chatClient->postReply($command, $this->getResponse($text));
 }
Esempio n. 7
0
 public function is(Command $command) : Promise
 {
     $reply = random_int(0, 1) ? "yes" : "no";
     if (!random_int(0, 15)) {
         $reply = "dunno";
     }
     $reply = $this->getRandomReply($reply);
     return $this->chatClient->postMessage($command->getRoom(), $reply);
 }
Esempio n. 8
0
 public function run(Command $command) : Generator
 {
     if (!$command->hasParameters()) {
         return $this->chatClient->postMessage($command->getRoom(), self::USAGE);
     }
     $form = (new FormBody())->addField("exp", implode(" ", $command->getParameters()));
     $request = (new Request())->setMethod("POST")->setUri("https://tryhaskell.org/eval")->setBody($form);
     $response = (yield $this->httpClient->request($request));
     return $this->chatClient->postMessage($command->getRoom(), $this->getMessage($response));
 }
Esempio n. 9
0
 public function random(Command $command) : \Generator
 {
     if (!$command->hasParameters()) {
         return new Success();
     }
     /** @var HttpResponse $response */
     $response = (yield $this->httpClient->request(self::API_BASE_URL . 'v1/gifs/random?' . http_build_query(['api_key' => $this->apiKey, 'rating' => $this->rating, 'tag' => implode(' ', $command->getParameters())])));
     $result = json_decode($response->getBody(), true);
     return $this->chatClient->postMessage($command->getRoom(), $this->getMessage($result));
 }
Esempio n. 10
0
 public function search(Command $command) : \Generator
 {
     if (!$command->hasParameters()) {
         return new Success();
     }
     /** @var HttpResponse $response */
     $response = (yield $this->httpClient->request('http://api.urbandictionary.com/v0/define?term=' . rawurlencode(implode(' ', $command->getParameters()))));
     $result = json_decode($response->getBody(), true);
     return $this->chatClient->postMessage($command->getRoom(), $this->getMessage($result), PostFlags::TRUNCATE);
 }
Esempio n. 11
0
 public function search(Command $command) : \Generator
 {
     if (!$command->hasParameters()) {
         return new Success();
     }
     $uri = "https://www.google.com/search?q=site:xkcd.com+intitle%3a%22xkcd%3a+%22+" . urlencode(implode(' ', $command->getParameters()));
     /** @var HttpResponse $response */
     $response = (yield $this->httpClient->request($uri));
     if ($response->getStatus() !== 200) {
         return $this->chatClient->postMessage($command->getRoom(), "Useless error message here so debugging this is harder than needed.");
     }
     $dom = domdocument_load_html($response->getBody());
     $nodes = (new \DOMXPath($dom))->query("//*[contains(concat(' ', normalize-space(@class), ' '), ' g ')]/h3/a");
     /** @var \DOMElement $node */
     foreach ($nodes as $node) {
         if (preg_match('~^/url\\?q=(https://xkcd\\.com/\\d+/)~', $node->getAttribute('href'), $matches)) {
             return $this->chatClient->postMessage($command->getRoom(), $matches[1]);
         }
     }
     if (preg_match('/^(\\d+)$/', trim(implode(' ', $command->getParameters())), $matches) !== 1) {
         return $this->chatClient->postMessage($command->getRoom(), self::NOT_FOUND_COMIC);
     }
     /** @var HttpResponse $response */
     $response = (yield $this->httpClient->request('https://xkcd.com/' . $matches[1]));
     if ($response->getStatus() !== 200) {
         return $this->chatClient->postMessage($command->getRoom(), self::NOT_FOUND_COMIC);
     }
     return $this->chatClient->postMessage($command->getRoom(), 'https://xkcd.com/' . $matches[1]);
 }
Esempio n. 12
0
 private function getVersion(CommandMessage $command) : \Generator
 {
     if (!(yield $command->getRoom()->isApproved())) {
         return;
     }
     $version = (new SebastianVersion(VERSION, APP_BASE))->getVersion();
     $messageText = preg_replace_callback('@v([0-9.]+)(?:-\\d+-g([0-9a-f]+))?@', function ($match) {
         return sprintf("[%s](%s)", $match[0], empty($match[2]) ? "https://github.com/Room-11/Jeeves/tree/v" . $match[1] : "https://github.com/Room-11/Jeeves/commit/" . $match[2]);
     }, $version);
     (yield $this->chatClient->postMessage($command->getRoom(), $messageText));
 }
Esempio n. 13
0
 public function search(Command $command) : \Generator
 {
     if (!$command->hasParameters()) {
         return new Success();
     }
     /** @var HttpResponse $response */
     $response = (yield $this->httpClient->request('https://developer.mozilla.org/en-US/search.json?highlight=false&q=' . rawurlencode(implode('%20', $command->getParameters()))));
     $result = json_decode($response->getBody(), true);
     if (!isset($result["documents"][0]["id"], $result["documents"][0]["url"])) {
         return $this->postNoResult($command);
     }
     return $this->postResult($command, $result["documents"][0]);
 }
Esempio n. 14
0
 protected function getCommitReference(Command $command, string $path)
 {
     list($user, $repo) = explode('/', $path, 2);
     /** @var HttpResponse $response */
     $response = (yield $this->httpClient->request(self::BASE_URL . '/repos/' . urlencode($user) . '/' . urlencode($repo) . '/git/refs/heads/master'));
     if ($response->getStatus() !== 200) {
         return $this->chatClient->postMessage($command->getRoom(), "Failed to fetch repo for {$path}");
     }
     $json = json_decode($response->getBody());
     if (!isset($json->object->sha)) {
         return $this->chatClient->postMessage($command->getRoom(), "Failed to fetch reference SHA for {$path}");
     }
     return $json->object->sha;
 }
Esempio n. 15
0
 public function search(Command $command) : \Generator
 {
     if (!$command->hasParameters()) {
         return new Success();
     }
     /** @var HttpResponse $response */
     $response = (yield $this->httpClient->request("https://man.freebsd.org/" . rawurlencode(implode("%20", $command->getParameters()))));
     $dom = domdocument_load_html($response->getBody());
     $xpath = new \DOMXPath($dom);
     if (!$this->isFound($xpath)) {
         return $this->postNoResult($command);
     }
     return $this->postResult($command, $xpath, $response->getRequest()->getUri());
 }
Esempio n. 16
0
 public function search(Command $command) : \Generator
 {
     if (!$command->hasParameters()) {
         return new Success();
     }
     /** @var HttpResponse $response */
     $response = (yield $this->makeAPIRequest(['titles' => implode(' ', $command->getParameters())]));
     $result = json_try_decode($response->getBody(), true);
     $firstHit = reset($result['query']['pages']);
     if (!isset($firstHit['pageid'])) {
         return $this->chatClient->postReply($command, 'Sorry I couldn\'t find that page.');
     }
     $response = (yield $this->makeAPIRequest(['prop' => 'info', 'inprop' => 'url', 'pageids' => $firstHit['pageid']]));
     $page = json_try_decode($response->getBody(), true);
     return $this->chatClient->postMessage($command->getRoom(), $page['query']['pages'][$firstHit['pageid']]['canonicalurl']);
 }
Esempio n. 17
0
 public function search(Command $command) : \Generator
 {
     if (!$command->hasParameters()) {
         return $this->chatClient->postReply($command, 'Mhm, I need a film title you want me to look for.');
     }
     $search = $command->getText();
     $message = (yield $this->chatClient->postMessage($command->getRoom(), sprintf('_Looking for \'%s\' for you…_', $search)));
     $params = $this->buildTitleSearchParams($search);
     // Send it out.
     /** @var HttpResponse $response */
     $response = (yield $this->httpClient->request(sprintf('%s?%s', self::OMDB_API_ENDPOINT, http_build_query($params))));
     /** @var \stdClass $data */
     $data = @json_decode($response->getBody());
     if (!$data || $data->Response === 'False') {
         return $this->chatClient->postMessage($command->getRoom(), 'I couldn\'t find anything for that title.');
     }
     $searchResults = [];
     foreach ($data->Search as $searchResult) {
         $searchResults[$searchResult->imdbID] = $searchResult;
     }
     // Only pick the top 3 results if needed.
     $searchResults = array_slice($searchResults, 0, 3, true);
     /** @var PostedMessage $chatMessage */
     (yield $this->chatClient->editMessage($message, $this->formatSearchResults($searchResults)));
     $requests = [];
     // Send out multiple http requests to get film descriptions and ratings.
     foreach ($searchResults as $id => $searchResult) {
         $requests[$id] = sprintf('%s?%s', self::OMDB_API_ENDPOINT, http_build_query($this->buildTitleDescParams($id)));
     }
     // Wait until all requests are done, allow failures.
     $allRequests = \Amp\some($this->httpClient->requestMulti($requests));
     list($errors, $responses) = (yield $allRequests);
     $descriptionResults = [];
     foreach ($responses as $key => $response) {
         $responseBody = @json_decode($response->getBody());
         if (!$responseBody || $responseBody->Response === 'False') {
             continue;
         }
         $descriptionResults[$key] = $responseBody;
     }
     return $this->chatClient->editMessage($message, $this->formatSearchResults($searchResults, $descriptionResults));
 }
Esempio n. 18
0
 public function search(Command $command) : \Generator
 {
     $info = explode('/', implode('/', $command->getParameters()), 2);
     if (count($info) !== 2) {
         return $this->chatClient->postReply($command, "Usage: `!!packagist vendor package`");
     }
     list($vendor, $package) = $info;
     $url = 'https://packagist.org/packages/' . urlencode($vendor) . '/' . urldecode($package) . '.json';
     try {
         /** @var HttpResponse $response */
         $response = (yield $this->httpClient->request($url));
         if ($response->getStatus() !== 200) {
             $response = (yield from $this->getResultFromSearchFallback($vendor, $package));
         }
         $data = json_try_decode($response->getBody());
         return $this->chatClient->postMessage($command->getRoom(), sprintf("[ [%s](%s) ] %s", $data->package->name, $data->package->repository, $data->package->description));
     } catch (\Throwable $e) {
         return $this->chatClient->postReply($command, 'No matching packages found');
     }
 }
Esempio n. 19
0
 private function execute(CommandMessage $command)
 {
     if (!(yield $command->getRoom()->isApproved())) {
         return;
     }
     if (!in_array($command->getParameter(0), self::ACTIONS, true)) {
         return;
     }
     if ($command->getParameter(0) === "list") {
         return yield from $this->list($command);
     }
     if (!(yield $this->storage->isAdmin($command->getRoom(), $command->getUserId()))) {
         return $this->chatClient->postReply($command, "I'm sorry Dave, I'm afraid I can't do that");
     }
     switch ($command->getParameter(0)) {
         case 'add':
             return yield from $this->add($command, (int) $command->getParameter(1));
         case 'remove':
             return yield from $this->remove($command, (int) $command->getParameter(1));
     }
     throw new \LogicException('Operation ' . $command->getParameter(0) . ' was considered valid but not handled??');
 }
Esempio n. 20
0
 public function unpin(Command $command)
 {
     $owners = (yield $this->chatClient->getRoomOwners($command->getRoom()));
     if (!isset($owners[$command->getUserId()])) {
         return $this->chatClient->postReply($command, "I'm sorry Dave, I'm afraid I can't do that");
     }
     if (!$command->hasParameters(1)) {
         return $this->chatClient->postReply($command, "You must supply a valid message ID to unpin");
     }
     if (!preg_match('#(?:messages?/)?([0-9]+)#', $command->getParameter(0), $match)) {
         return $this->chatClient->postReply($command, "You must supply a valid message ID to unpin");
     }
     $key = $match[1];
     $id = (int) $key;
     if (!(yield $this->keyValueStore->exists($key, $command->getRoom()))) {
         return $this->chatClient->postReply($command, "You must supply a valid message ID to unpin");
     }
     (yield $this->keyValueStore->unset($key, $command->getRoom()));
     if (in_array($id, (yield $this->chatClient->getPinnedMessages($command->getRoom())))) {
         (yield $this->chatClient->pinOrUnpinMessage($id, $command->getRoom()));
     }
     return $this->chatClient->postMessage($command->getRoom(), "I will no longer repin message #{$id}");
 }
Esempio n. 21
0
 public function getRFC(Command $command)
 {
     $rfc = $command->getParameter(0);
     if ($rfc === null) {
         // e.g.: !!rfc pipe-operator
         return $this->chatClient->postMessage($command->getRoom(), "RFC id required");
     }
     $uri = self::BASE_URI . '/' . urlencode($rfc);
     /** @var HttpResponse $response */
     $response = (yield $this->httpClient->request($uri));
     if ($response->getStatus() !== 200) {
         return $this->chatClient->postMessage($command->getRoom(), "Nope, we can't have nice things.");
     }
     $votes = self::parseVotes($response->getBody());
     if (empty($votes)) {
         return $this->chatClient->postMessage($command->getRoom(), "No votes found");
     }
     $messages = [];
     foreach ($votes as $id => $vote) {
         $breakdown = [];
         $total = array_sum($vote['votes']);
         if ($total > 0) {
             foreach ($vote['votes'] as $option => $value) {
                 $breakdown[] = sprintf("%s (%d: %d%%)", $option, $value, 100 * $value / $total);
             }
         }
         $messages[] = ['name' => $vote['name'], 'href' => $uri . '#' . $id, 'breakdown' => implode(', ', $breakdown)];
     }
     if (count($messages) === 1) {
         return $this->chatClient->postMessage($command->getRoom(), sprintf("[tag:rfc-vote] [%s](%s) %s", $messages[0]['name'], $messages[0]['href'], $messages[0]['breakdown']));
     }
     $message = implode("\n", array_map(function ($message) {
         return sprintf('%s %s - %s (%s)', self::BULLET, $message['name'], $message['breakdown'], $message['href']);
     }, $messages));
     return $this->chatClient->postMessage($command->getRoom(), $message);
 }
Esempio n. 22
0
 public function handleCommand(Command $command) : Promise
 {
     return resolve(function () use($command) {
         $commandName = $command->getCommandName();
         if (!isset($this->commands[$commandName])) {
             return;
         }
         $eventId = $command->getEvent()->getId();
         $userId = $command->getUserId();
         try {
             $userIsBanned = (yield $this->banStorage->isBanned($command->getRoom(), $userId));
             if ($userIsBanned) {
                 $this->logger->log(Level::DEBUG, "User #{$userId} is banned, ignoring event #{$eventId} for built in commands");
                 return;
             }
             $this->logger->log(Level::DEBUG, "Passing event #{$eventId} to built in command handler " . get_class($this->commands[$commandName]));
             (yield $this->commands[$commandName]->handleCommand($command));
         } catch (\Throwable $e) {
             $this->logger->log(Level::ERROR, "Something went wrong while handling #{$eventId} for built-in commands: {$e}");
         }
     });
 }
Esempio n. 23
0
 /**
  * Example:
  *   !!github Room-11/Jeeves
  *
  * [tag:github-repo] [Room-11/Jeeves](https://github.com/Room-11/Jeeves) Chatbot attempt -
  *    - Watchers: 14, Forks: 15, Last Pushed: 2016-05-26T08:57:41Z
  *
  * @param Command $command
  * @param string $path
  * @return \Generator
  */
 protected function repo(Command $command, string $path) : \Generator
 {
     list($user, $repo) = explode('/', $path, 2);
     /** @var HttpResponse $response */
     $response = (yield $this->httpClient->request('https://api.github.com/repos/' . urlencode($user) . '/' . urlencode($repo)));
     if ($response->getStatus() !== 200) {
         return $this->chatClient->postMessage($command->getRoom(), "Failed fetching repo for {$path}");
     }
     $json = json_decode($response->getBody());
     if (!isset($json->id)) {
         return $this->chatClient->postMessage($command->getRoom(), "Unknown repo {$path}");
     }
     return $this->chatClient->postMessage($command->getRoom(), sprintf("[tag:github-repo] [%s](%s) %s - Watchers: %d, Forks: %d, Last Push: %s", $json->full_name, $json->html_url, $json->description, $json->watchers, $json->forks, $json->pushed_at));
 }
Esempio n. 24
0
 public function fetch(Command $command) : \Generator
 {
     $response = (yield $this->httpClient->request(self::API_URL));
     return $this->chatClient->postMessage($command->getRoom(), $this->getMessage($response));
 }
Esempio n. 25
0
 public function search(Command $command) : \Generator
 {
     if (!$command->hasParameters()) {
         return new Success();
     }
     $text = implode(' ', $command->getParameters());
     $searchTerm = (yield $this->messageResolver->resolveMessageText($command->getRoom(), $text));
     $uri = $this->getSearchURL($searchTerm);
     $request = (new HttpRequest())->setMethod('GET')->setUri($uri)->setHeader('User-Agent', self::USER_AGENT);
     /** @var HttpResponse $response */
     $response = (yield $this->httpClient->request($request));
     if ($response->getStatus() !== 200) {
         return $this->chatClient->postMessage($command->getRoom(), "Google responded with {$response->getStatus()}");
     }
     if (preg_match('#charset\\s*=\\s*([^;]+)#i', trim(implode(', ', $response->getHeader('Content-Type'))), $match) && !preg_match('/' . preg_quote(self::ENCODING, '/') . '/i', $match[1])) {
         $body = iconv($match[1], self::ENCODING, $response->getBody());
     }
     if (empty($body)) {
         $body = $response->getBody();
     }
     $dom = domdocument_load_html($body);
     $xpath = new \DOMXPath($dom);
     $nodes = $this->getResultNodes($xpath);
     if ($nodes->length === 0) {
         return $this->postNoResultsMessage($command);
     }
     $searchResults = $this->getSearchResults($nodes, $xpath);
     $postMessage = $this->getPostMessage($searchResults, $uri, $searchTerm);
     return $this->chatClient->postMessage($command->getRoom(), $postMessage);
 }
Esempio n. 26
0
 public function toLanguage(Command $command, string $toLanguage = null) : \Generator
 {
     $params = $command->getParameters();
     if ($params[0] === 'list') {
         return $this->postSupportedLanguagesList($command->getRoom());
     }
     $toLanguage = $toLanguage ?? array_shift($params);
     if (null === ($toLanguageCode = $this->getLanguageCode($toLanguage ?? array_shift($params)))) {
         return $this->chatClient->postReply($command, 'Sorry, I don\'t speak ' . $toLanguage);
     }
     $fromLanguageCode = null;
     if (preg_match('#^--from(?:=(.+))?$#', $params[0] ?? '', $match)) {
         array_shift($params);
         $fromLanguage = empty($match[1]) ? array_shift($params) : $match[1];
         if (null === ($fromLanguageCode = $this->getLanguageCode($fromLanguage))) {
             return $this->chatClient->postReply($command, 'Sorry, I don\'t speak ' . $fromLanguage);
         }
     }
     if (count($params) < 1) {
         return $this->chatClient->postReply($command, 'The empty string is the same in every language');
     }
     $text = (yield from $this->getTextFromArguments($command->getRoom(), $params));
     $translation = (yield from $this->getTranslation($command->getRoom(), $text, $toLanguageCode, $fromLanguageCode));
     return $this->chatClient->postMessage($command->getRoom(), $translation);
 }
Esempio n. 27
0
 public function trenslete(CommandMessage $command)
 {
     $text = (yield $this->messageResolver->resolveMessageText($command->getRoom(), $command->getText()));
     return $this->chatClient->postReply($command, $this->ruinPrepositions($text));
 }
Esempio n. 28
0
 public function getExamples(Command $command) : Promise
 {
     $examples = "Examples: \n" . Chars::BULLET . " !!reminder foo at 18:00 \n" . Chars::BULLET . " With timezone: (ie. UTC-3) !!reminder foo at 18:00-3:00 \n" . Chars::BULLET . " !!reminder bar in 2 hours \n" . Chars::BULLET . " !!reminder unset 32901146 \n" . Chars::BULLET . " !!reminder list \n" . Chars::BULLET . " !!in 2 days 42 hours 42 minutes 42 seconds 42! \n" . Chars::BULLET . " !!at 22:00 Grab a beer!";
     return resolve(function () use($command, $examples) {
         return $this->chatClient->postMessage($command->getRoom(), $examples);
     });
 }
Esempio n. 29
0
 /**
  * Handle a command message
  *
  * @param Command $command
  * @return Promise
  */
 public function handleCommand(Command $command) : Promise
 {
     if ($command->getParameter(0) === "list") {
         return $this->getSupportedCanonicals($command);
     }
     if (!in_array($command->getParameter(0), self::ACTIONS)) {
         return $this->getMessage($command, implode(" ", $command->getParameters()));
     }
     return resolve(function () use($command) {
         if (!(yield $this->admin->isAdmin($command->getRoom(), $command->getUserId()))) {
             return $this->chatClient->postReply($command, "I'm sorry Dave, I'm afraid I can't do that.");
         }
         switch ($command->getParameter(0)) {
             case 'add':
                 return (yield $this->add($command, (string) $command->getParameter(1), (string) $command->getParameter(2)));
             case 'remove':
                 return (yield $this->remove($command, (string) $command->getParameter(1)));
             case 'fire':
                 return (yield $this->fire($command));
         }
     });
 }
Esempio n. 30
0
 public function tweet(Command $command)
 {
     if (!$this->isMessageValid($command->getParameter(0))) {
         return new Success();
     }
     if (!(yield $this->admin->isAdmin($command->getRoom(), $command->getUserId()))) {
         return $this->chatClient->postReply($command, "I'm sorry Dave, I'm afraid I can't do that");
     }
     $tweetText = (yield from $this->getMessage($command, $command->getParameters()[0]));
     if (mb_strlen($tweetText, "UTF-8") > 140) {
         return $this->chatClient->postReply($command, "Boo! The message exceeds the 140 character limit. :-(");
     }
     $keys = ['oauth.consumer_key', 'oauth.access_token', 'oauth.consumer_secret', 'oauth.access_token_secret'];
     $config = [];
     foreach ($keys as $key) {
         if (!(yield $this->storage->exists($key, $command->getRoom()))) {
             return $this->chatClient->postReply($command, "I'm not currently configured for tweeting :-(");
         }
         $config[$key] = (yield $this->storage->get($key, $command->getRoom()));
     }
     $oauthParameters = ["oauth_consumer_key" => $config['oauth.consumer_key'], "oauth_token" => $config['oauth.access_token'], "oauth_nonce" => $this->getNonce(), "oauth_timestamp" => (new \DateTimeImmutable())->format("U"), "oauth_signature_method" => "HMAC-SHA1", "oauth_version" => "1.0", "status" => $tweetText];
     $oauthParameters = array_map("rawurlencode", $oauthParameters);
     asort($oauthParameters);
     ksort($oauthParameters);
     $queryString = urldecode(http_build_query($oauthParameters, '', '&'));
     $baseString = "POST&" . rawurlencode(self::BASE_URI . "/statuses/update.json") . "&" . rawurlencode($queryString);
     $key = $config['oauth.consumer_secret'] . "&" . $config['oauth.access_token_secret'];
     $signature = rawurlencode(base64_encode(hash_hmac('sha1', $baseString, $key, true)));
     $oauthParameters["oauth_signature"] = $signature;
     $oauthParameters = array_map(function ($value) {
         return '"' . $value . '"';
     }, $oauthParameters);
     unset($oauthParameters["status"]);
     asort($oauthParameters);
     ksort($oauthParameters);
     $authorizationHeader = $auth = "OAuth " . urldecode(http_build_query($oauthParameters, '', ', '));
     $request = (new HttpRequest())->setUri(self::BASE_URI . "/statuses/update.json")->setMethod('POST')->setProtocol('1.1')->setBody('status=' . urlencode($tweetText))->setAllHeaders(['Authorization' => $authorizationHeader, 'Content-Type' => 'application/x-www-form-urlencoded']);
     /** @var HttpResponse $result */
     $result = (yield $this->httpClient->request($request));
     $tweetInfo = json_decode($result->getBody(), true);
     $tweetUri = 'https://twitter.com/' . $tweetInfo['user']['screen_name'] . '/status/' . $tweetInfo['id_str'];
     return $this->chatClient->postMessage($command->getRoom(), $tweetUri);
 }