public FriendsFeed(String id, final String ownerUserId, final String viewingUserId) {
    super(id);

    log.debug("FriendsFeed()");

    // heading
    Label heading = new Label("heading");

    if (viewingUserId.equals(ownerUserId)) {
      heading.setDefaultModel(new ResourceModel("heading.widget.my.friends"));
    } else {
      String displayName = sakaiProxy.getUserDisplayName(ownerUserId);
      heading.setDefaultModel(
          new StringResourceModel("heading.widget.view.friends", null, new Object[] {displayName}));
    }
    add(heading);

    // get our list of friends as an IDataProvider
    // the FriendDataProvider takes care of the privacy associated with the associated list
    // so what it returns will always be clean
    FriendsFeedDataProvider provider = new FriendsFeedDataProvider(ownerUserId);

    GridView<Person> dataView =
        new GridView<Person>("rows", provider) {

          private static final long serialVersionUID = 1L;

          @Override
          protected void populateEmptyItem(Item<Person> item) {
            Link friendItem =
                new Link("friendsFeedItem") {
                  private static final long serialVersionUID = 1L;

                  public void onClick() {}
                };

            friendItem.add(
                new ProfileImageRenderer(
                    "friendPhoto",
                    null,
                    null,
                    null,
                    ProfileConstants.PROFILE_IMAGE_THUMBNAIL,
                    true));

            friendItem.add(new Label("friendName", "empty"));
            item.add(friendItem);
            friendItem.setVisible(false);
          }

          protected void populateItem(Item<Person> item) {
            final Person person = (Person) item.getDefaultModelObject();
            final String friendId = person.getUuid();

            // setup info
            String displayName = person.getDisplayName();
            boolean friend;

            // get friend status
            if (ownerUserId.equals(viewingUserId)) {
              friend = true; // viewing own list of friends so must be a friend
            } else {
              friend =
                  connectionsLogic.isUserXFriendOfUserY(
                      viewingUserId, friendId); // other person viewing, check if they are friends
            }

            // link to their profile
            Link<String> friendItem =
                new Link<String>("friendsFeedItem") {
                  private static final long serialVersionUID = 1L;

                  public void onClick() {
                    // link to own profile if link will point to self
                    if (viewingUserId.equals(friendId)) {
                      setResponsePage(new MyProfile());
                    } else {
                      setResponsePage(new ViewProfile(friendId));
                    }
                  }
                };

            /* IMAGE */
            friendItem.add(
                new ProfileImageRenderer(
                    "friendPhoto",
                    friendId,
                    person.getPreferences(),
                    person.getPrivacy(),
                    ProfileConstants.PROFILE_IMAGE_THUMBNAIL,
                    true));

            // name (will be linked also)
            Label friendLinkLabel = new Label("friendName", displayName);
            friendItem.add(friendLinkLabel);

            item.add(friendItem);
          }
        };

    dataView.setColumns(3);
    add(dataView);

    /* NUM FRIENDS LABEL (can't just use provider as it only ever returns the number in the grid */
    final int numFriends = connectionsLogic.getConnectionsForUserCount(ownerUserId);
    Label numFriendsLabel = new Label("numFriendsLabel");
    add(numFriendsLabel);

    /* VIEW ALL FRIENDS LINK */
    Link<String> viewFriendsLink =
        new Link<String>("viewFriendsLink") {
          private static final long serialVersionUID = 1L;

          public void onClick() {
            // this could come from a bookmarkablelink, but this works for now
            if (numFriends == 0) {
              setResponsePage(new MySearch());
            } else {
              // if own FriendsFeed, link to own MyFriends, otherwise link to ViewFriends
              if (sakaiProxy.isSuperUserAndProxiedToUser(ownerUserId)) {
                setResponsePage(new ViewFriends(ownerUserId));
              } else if (viewingUserId.equals(ownerUserId)) {
                setResponsePage(new MyFriends());
              } else {
                setResponsePage(new ViewFriends(ownerUserId));
              }
            }
          }
        };
    Label viewFriendsLabel = new Label("viewFriendsLabel");
    viewFriendsLink.add(viewFriendsLabel);
    add(viewFriendsLink);

    /* TESTS FOR THE ABOVE to change labels and links */
    if (numFriends == 0) {
      numFriendsLabel.setDefaultModel(new ResourceModel("text.friend.feed.num.none"));
      // numFriendsLabel.setVisible(false);
      // if own FriendsFeed, show search link, otherwise hide
      if (viewingUserId.equals(ownerUserId)) {
        viewFriendsLabel.setDefaultModel(new ResourceModel("link.friend.feed.search"));
      } else {
        viewFriendsLink.setVisible(false);
      }
    } else if (numFriends == 1) {
      numFriendsLabel.setDefaultModel(new ResourceModel("text.friend.feed.num.one"));
      viewFriendsLink.setVisible(false);
    } else {
      numFriendsLabel.setDefaultModel(
          new StringResourceModel("text.friend.feed.num.many", null, new Object[] {numFriends}));
      viewFriendsLabel.setDefaultModel(new ResourceModel("link.friend.feed.view"));
    }
  }
 /**
  * Get the number of columns.
  *
  * @return
  */
 public int getColumns() {
   return repeater.getColumns();
 }