@WebMethod("friend/show")
  public RecordSet showFriends(QueryParams qp) {
    final int DEFAULT_USER_COUNT_IN_PAGE = 20;

    FriendshipLogic fs = GlobalLogics.getFriendship();

    Context ctx = WutongContext.getContext(qp, true);
    String userId = qp.getString("user", ctx.getViewerIdString());
    String cols =
        qp.getString(
            "columns",
            "user_id, display_name, remark,perhaps_name,image_url, status, gender, in_circles, his_friend, bidi,pedding_requests,profile_privacy");
    if (cols.equals("#full")) cols = AccountLogic.USER_STANDARD_COLUMNS;
    boolean withPublicCircles = qp.getBoolean("with_public_circles", false);
    if (!withPublicCircles)
      return fs.getFriendsP(
          ctx,
          ctx.getViewerIdString(),
          userId,
          qp.getString("circles", Integer.toString(FRIENDS_CIRCLE)),
          cols,
          qp.getBoolean("in_public_circles", false),
          (int) qp.getInt("page", 0),
          (int) qp.getInt("count", DEFAULT_USER_COUNT_IN_PAGE));
    else
      return fs.getFriendsV2P(
          ctx,
          ctx.getViewerIdString(),
          userId,
          qp.getString("circles", Integer.toString(FRIENDS_CIRCLE)),
          cols,
          (int) qp.getInt("page", 0),
          (int) qp.getInt("count", DEFAULT_USER_COUNT_IN_PAGE));
  }
  @WebMethod("relation/bidi")
  public Record getBidiRelation(QueryParams qp) {
    FriendshipLogic fs = GlobalLogics.getFriendship();

    Context ctx = WutongContext.getContext(qp, true);
    String userId = qp.getString("source", ctx.getViewerIdString());
    return fs.getBidiRelation(
        ctx,
        userId,
        qp.checkGetString("target"),
        qp.getString("circle", Integer.toString(FRIENDS_CIRCLE)));
  }
  @WebMethod("remark/set")
  public boolean setUserRemark(QueryParams qp) {
    FriendshipLogic fs = GlobalLogics.getFriendship();

    Context ctx = WutongContext.getContext(qp, true);
    return fs.setRemark(
        ctx, ctx.getViewerIdString(), qp.checkGetString("friend"), qp.getString("remark", ""));
  }
  @WebMethod("follower/show")
  public RecordSet showFollowers(QueryParams qp) {
    final int DEFAULT_USER_COUNT_IN_PAGE = 20;

    FriendshipLogic fs = GlobalLogics.getFriendship();

    Context ctx = WutongContext.getContext(qp, true);
    String userId = qp.getString("user", ctx.getViewerIdString());
    return fs.getFollowersP(
        ctx,
        ctx.getViewerIdString(),
        userId,
        qp.getString("circles", Integer.toString(FRIENDS_CIRCLE)),
        qp.getString(
            "columns",
            "user_id, display_name, remark,perhaps_name,image_url, status, gender, in_circles, his_friend, bidi,pedding_requests,profile_privacy"),
        (int) qp.getInt("page", 0),
        (int) qp.getInt("count", DEFAULT_USER_COUNT_IN_PAGE));
  }
  @WebMethod("circle/show")
  public RecordSet showCircles(QueryParams qp) {
    FriendshipLogic fs = GlobalLogics.getFriendship();
    GroupLogic group = GlobalLogics.getGroup();

    Context ctx = WutongContext.getContext(qp, false);
    String userId = qp.getString("user", ctx.getViewerIdString());

    boolean withPublicCircles = qp.getBoolean("with_public_circles", false);
    if (!withPublicCircles) {
      RecordSet recs =
          fs.getCircles(
              ctx, userId, qp.getString("circles", ""), qp.getBoolean("with_users", false));
      attachSubscribe(ctx, recs);
      return recs;
    } else {
      String circleIds = qp.getString("circles", "");
      boolean withMembers = qp.getBoolean("with_users", false);
      List<String> circles = StringUtils2.splitList(circleIds, ",", true);
      List<String> groups = group.getGroupIdsFromMentions(ctx, circles);
      circles.removeAll(groups);
      RecordSet recs =
          fs.getCirclesP(ctx, userId, StringUtils2.joinIgnoreBlank(",", circles), withMembers);
      RecordSet recs0 =
          group.getGroups(
              ctx,
              PUBLIC_CIRCLE_ID_BEGIN,
              PUBLIC_CIRCLE_ID_END,
              ctx.getViewerIdString(),
              StringUtils2.joinIgnoreBlank(",", groups),
              GROUP_LIGHT_COLS + ",circle_ids,formal,subtype,parent_id",
              withMembers);
      recs0.renameColumn(GRP_COL_ID, "circle_id");
      recs0.renameColumn(GRP_COL_NAME, "circle_name");
      for (Record rec : recs) rec.put("type", CIRCLE_TYPE_LOCAL);
      for (Record rec : recs0) rec.put("type", CIRCLE_TYPE_PUBLIC);
      recs.addAll(recs0);

      attachSubscribe(ctx, recs);
      return recs;
    }
  }
  @WebMethod("friend/both")
  public RecordSet getBothFriends(QueryParams qp) {
    final int DEFAULT_USER_COUNT_IN_PAGE = 20;

    FriendshipLogic fs = GlobalLogics.getFriendship();

    Context ctx = WutongContext.getContext(qp, true);
    String userId = qp.getString("user", ctx.getViewerIdString());
    return fs.getBothFriendsP(
        ctx,
        ctx.getViewerIdString(),
        userId,
        (int) qp.getInt("page", 0),
        (int) qp.getInt("count", DEFAULT_USER_COUNT_IN_PAGE));
  }
  @WebMethod("friend/contactset")
  public Record setContactFriends(QueryParams qp, HttpServletRequest req)
      throws UnsupportedEncodingException {
    FriendshipLogic fs = GlobalLogics.getFriendship();
    AccountLogic account = GlobalLogics.getAccount();

    Context ctx = WutongContext.getContext(qp, true);

    Record rec = account.findUidLoginNameNotInID(ctx, qp.checkGetString("content"));
    String fid = "";
    String hasVirtualFriendId =
        fs.getUserFriendHasVirtualFriendId(
            ctx, ctx.getViewerIdString(), qp.checkGetString("content"));
    if (rec.isEmpty() && hasVirtualFriendId.equals("0")) {
      fid =
          fs.setContactFriendP(
              ctx,
              ctx.getViewerIdString(),
              qp.checkGetString("name"),
              qp.checkGetString("content"),
              qp.checkGetString("circleIds"),
              Constants.FRIEND_REASON_MANUALSELECT);
      return account.getUser(
          ctx,
          ctx.getViewerIdString(),
          fid,
          qp.getString("columns", AccountLogic.USER_LIGHT_COLUMNS));
    } else {
      fid = !rec.isEmpty() ? rec.getString("user_id") : hasVirtualFriendId;
      return fs.setFriendP(
          ctx,
          ctx.getViewerIdString(),
          fid,
          qp.checkGetString("circleIds"),
          Constants.FRIEND_REASON_MANUALSELECT);
    }
  }