private SlackChannel getIMChannelForUser(SlackUser user) {
   List<SlackChannel> imcs = getAllIMChannels();
   for (SlackChannel channel : imcs) {
     if (channel.getMembers().contains(user)) {
       return channel;
     }
   }
   SlackMessageHandle<SlackChannelReply> reply = openDirectMessageChannel(user);
   return reply.getReply().getSlackChannel();
 }
 private List<SlackChannel> getAllIMChannels() {
   Collection<SlackChannel> allChannels = getChannels();
   List<SlackChannel> iMChannels = new ArrayList<>();
   for (SlackChannel channel : allChannels) {
     if (channel.isDirect()) {
       iMChannels.add(channel);
     }
   }
   return iMChannels;
 }
  @Override
  public SlackMessageHandle sendMessage(
      SlackChannel channel,
      String message,
      SlackAttachment attachment,
      SlackChatConfiguration chatConfiguration) {
    SlackMessageHandleImpl handle = new SlackMessageHandleImpl(getNextMessageId());
    Map<String, String> arguments = new HashMap<>();
    arguments.put("token", authToken);
    arguments.put("channel", channel.getId());
    arguments.put("text", message);
    if (chatConfiguration.asUser) {
      arguments.put("as_user", "true");
    }
    if (chatConfiguration.avatar == Avatar.ICON_URL) {
      arguments.put("icon_url", chatConfiguration.avatarDescription);
    }
    if (chatConfiguration.avatar == Avatar.EMOJI) {
      arguments.put("icon_emoji", chatConfiguration.avatarDescription);
    }
    if (chatConfiguration.userName != null) {
      arguments.put("username", chatConfiguration.userName);
    }
    if (attachment != null) {
      arguments.put(
          "attachments", SlackJSONAttachmentFormatter.encodeAttachments(attachment).toString());
    }

    postSlackCommand(arguments, CHAT_POST_MESSAGE_COMMAND, handle);
    return handle;
  }
 @Override
 public void run() {
   try {
     if (!gerritChangeInfoService.projectExists(projectId)) {
       session.sendMessage(
           channelToSubscribe,
           "Could not find project name *`"
               + projectId
               + "`*, check that this project name is valid and that it is active",
           null,
           SlackChatConfiguration.getConfiguration().asUser());
       return;
     }
     subscriptionService.unsubscribeOnProject(projectId, channelToSubscribe.getId());
     session.sendMessage(
         channelToSubscribe,
         "This channel will not publish any more review requests from project *`"
             + projectId
             + "`*",
         null,
         SlackChatConfiguration.getConfiguration().asUser());
   } catch (IOException e) {
     session.sendMessage(
         channelToSubscribe,
         "Too bad, an unexpected error occurred...",
         null,
         SlackChatConfiguration.getConfiguration().asUser());
     e.printStackTrace();
   }
 }
 @Override
 public SlackMessageHandle leaveChannel(SlackChannel channel) {
   SlackMessageHandleImpl handle = new SlackMessageHandleImpl(getNextMessageId());
   Map<String, String> arguments = new HashMap<>();
   arguments.put("token", authToken);
   arguments.put("channel", channel.getId());
   postSlackCommand(arguments, CHANNELS_LEAVE_COMMAND, handle);
   return handle;
 }
 @Override
 public SlackMessageHandle deleteMessage(String timeStamp, SlackChannel channel) {
   SlackMessageHandleImpl handle = new SlackMessageHandleImpl(getNextMessageId());
   Map<String, String> arguments = new HashMap<>();
   arguments.put("token", authToken);
   arguments.put("channel", channel.getId());
   arguments.put("ts", timeStamp);
   postSlackCommand(arguments, CHAT_DELETE_COMMAND, handle);
   return handle;
 }
 @Override
 public SlackMessageHandle<SlackChannelReply> inviteToChannel(
     SlackChannel channel, SlackUser user) {
   SlackMessageHandleImpl<SlackChannelReply> handle =
       new SlackMessageHandleImpl<SlackChannelReply>(getNextMessageId());
   Map<String, String> arguments = new HashMap<>();
   arguments.put("token", authToken);
   arguments.put("channel", channel.getId());
   arguments.put("user", user.getId());
   postSlackCommand(arguments, CHANNELS_INVITE_COMMAND, handle);
   return handle;
 }
 @Override
 public SlackMessageHandle addReactionToMessage(
     SlackChannel channel, String messageTimeStamp, String emojiCode) {
   SlackMessageHandleImpl handle = new SlackMessageHandleImpl(getNextMessageId());
   Map<String, String> arguments = new HashMap<>();
   arguments.put("token", authToken);
   arguments.put("channel", channel.getId());
   arguments.put("timestamp", messageTimeStamp);
   arguments.put("name", emojiCode);
   postSlackCommand(arguments, REACTIONS_ADD_COMMAND, handle);
   return handle;
 }
 @Override
 public SlackMessageHandle<SlackMessageReply> updateMessage(
     String timeStamp, SlackChannel channel, String message) {
   SlackMessageHandleImpl<SlackMessageReply> handle =
       new SlackMessageHandleImpl<SlackMessageReply>(getNextMessageId());
   Map<String, String> arguments = new HashMap<>();
   arguments.put("token", authToken);
   arguments.put("ts", timeStamp);
   arguments.put("channel", channel.getId());
   arguments.put("text", message);
   postSlackCommand(arguments, CHAT_UPDATE_COMMAND, handle);
   return handle;
 }
 @Override
 public SlackMessageHandle sendMessageOverWebSocket(
     SlackChannel channel, String message, SlackAttachment attachment) {
   SlackMessageHandleImpl handle = new SlackMessageHandleImpl(getNextMessageId());
   try {
     JSONObject messageJSON = new JSONObject();
     messageJSON.put("type", "message");
     messageJSON.put("channel", channel.getId());
     messageJSON.put("text", message);
     if (attachment != null) {
       messageJSON.put("attachments", SlackJSONAttachmentFormatter.encodeAttachments(attachment));
     }
     websocketSession.getBasicRemote().sendText(messageJSON.toJSONString());
   } catch (Exception e) {
     // TODO : improve exception handling
     e.printStackTrace();
   }
   return handle;
 }