docs: function(params, callbacks, recursiveCallback) {
                  /**
                   * + ChatMessage        {object}
                   *    - token           {string}
                   *    - tokenIssuer     {string}
                   *    - type            {int}
                   *    - typeCode        {string}
                   *    - messageType     {int}
                   *    - subjectId       {long}
                   *    - uniqueId        {string}
                   *    - content         {string}
                   *    - time            {long}
                   *    - medadata        {string}
                   *    - systemMedadata  {string}
                   *    - repliedTo       {long}
                   */
  
                  var asyncPriority = (params.asyncPriority > 0)
                      ? params.asyncPriority
                      : msgPriority;
  
                  var messageVO = {
                      type: params.chatMessageVOType,
                      token: token,
                      tokenIssuer: 1
                  };
  
                  var threadId = params.subjectId;
  
                  if (params.typeCode) {
                      messageVO.typeCode = params.typeCode;
                  }
                  else if (generalTypeCode) {
                      messageVO.typeCode = generalTypeCode;
                  }
  
                  if (params.messageType) {
                      messageVO.messageType = params.messageType;
                  }
  
                  if (params.subjectId) {
                      messageVO.subjectId = params.subjectId;
                  }
  
                  if (params.content) {
                      if (typeof params.content == 'object') {
                          messageVO.content = JSON.stringify(params.content);
                      }
                      else {
                          messageVO.content = params.content;
                      }
                  }
  
                  if (params.metadata) {
                      messageVO.metadata = params.metadata;
                  }
  
                  if (params.systemMetadata) {
                      messageVO.systemMetadata = params.systemMetadata;
                  }
  
                  if (params.repliedTo) {
                      messageVO.repliedTo = params.repliedTo;
                  }
  
                  var uniqueId;
  
                  if (typeof params.uniqueId != 'undefined') {
                      uniqueId = params.uniqueId;
                  }
                  else if (params.chatMessageVOType !== chatMessageVOTypes.PING) {
                      uniqueId = Utility.generateUUID();
                  }
  
                  if (Array.isArray(uniqueId)) {
                      messageVO.uniqueId = JSON.stringify(uniqueId);
                  }
                  else {
                      messageVO.uniqueId = uniqueId;
                  }
  
                  if (typeof callbacks == 'object') {
                      if (callbacks.onSeen || callbacks.onDeliver || callbacks.onSent) {
                          if (!threadCallbacks[threadId]) {
                              threadCallbacks[threadId] = {};
                          }
  
                          threadCallbacks[threadId][uniqueId] = {};
  
                          sendMessageCallbacks[uniqueId] = {};
  
                          if (callbacks.onSent) {
                              sendMessageCallbacks[uniqueId].onSent = callbacks.onSent;
                              threadCallbacks[threadId][uniqueId].onSent = false;
                              threadCallbacks[threadId][uniqueId].uniqueId = uniqueId;
                          }
  
                          if (callbacks.onSeen) {
                              sendMessageCallbacks[uniqueId].onSeen = callbacks.onSeen;
                              threadCallbacks[threadId][uniqueId].onSeen = false;
                          }
  
                          if (callbacks.onDeliver) {
                              sendMessageCallbacks[uniqueId].onDeliver = callbacks.onDeliver;
                              threadCallbacks[threadId][uniqueId].onDeliver = false;
                          }
  
                      }
                      else if (callbacks.onResult) {
                          messagesCallbacks[uniqueId] = callbacks.onResult;
                      }
                  }
                  else if (typeof callbacks == 'function') {
                      messagesCallbacks[uniqueId] = callbacks;
                  }
  
                  /**
                   * Message to send through async SDK
                   *
                   * + MessageWrapperVO  {object}
                   *    - type           {int}       Type of ASYNC message based on content
                   *    + content        {string}
                   *       -peerName     {string}    Name of receiver Peer
                   *       -receivers[]  {long}      Array of receiver peer ids (if you use this, peerName will be ignored)
                   *       -priority     {int}       Priority of message 1-10, lower has more priority
                   *       -messageId    {long}      Id of message on your side, not required
                   *       -ttl          {long}      Time to live for message in milliseconds
                   *       -content      {string}    Chat Message goes here after stringifying
                   *    - trackId        {long}      Tracker id of message that you receive from DIRANA previously (if you are replying a sync message)
                   */
  
                  var data = {
                      type: (parseInt(params.pushMsgType) > 0)
                          ? params.pushMsgType
                          : 3,
                      content: {
                          peerName: serverName,
                          priority: asyncPriority,
                          content: JSON.stringify(messageVO),
                          ttl: (params.messageTtl > 0)
                              ? params.messageTtl
                              : messageTtl
                      }
                  };
  
                  asyncClient.send(data, function(res) {
                      if (res.hasError && callbacks) {
                          if (typeof callbacks == 'function') {
                              callbacks(res);
                          }
                          else if (typeof callbacks == 'object' && typeof callbacks.onResult == 'function') {
                              callbacks.onResult(res);
                          }
  
                          if (messagesCallbacks[uniqueId]) {
                              delete messagesCallbacks[uniqueId];
                          }
                      }
                  });
  
                  sendPingTimeout && clearTimeout(sendPingTimeout);
                  sendPingTimeout = setTimeout(function() {
                      ping();
                  }, chatPingMessageInterval);
  
                  recursiveCallback && recursiveCallback();
  
                  return {
                      uniqueId: uniqueId,
                      threadId: threadId,
                      participant: userInfo,
                      content: params.content
                  };
              }