Changeset 36080
- Timestamp:
- 12/06/09 13:35:10 (3 years ago)
- Location:
- lang/java/misc/hatenahaiku4j/branches/for-HTML-scraping/src/hatenahaiku4j
- Files:
-
- 5 modified
-
EntityAPI.java (modified) (2 diffs)
-
HatenaHaikuAPI.java (modified) (6 diffs)
-
HatenaHaikuAPIHTML.java (modified) (21 diffs)
-
HatenaHaikuAPILight.java (modified) (16 diffs)
-
sample/Sample001.java (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
lang/java/misc/hatenahaiku4j/branches/for-HTML-scraping/src/hatenahaiku4j/EntityAPI.java
r35677 r36080 1 1 package hatenahaiku4j; 2 3 import hatenahaiku4j.op.CollectOp; 4 5 import java.util.ArrayList; 6 import java.util.List; 2 7 3 8 /** … … 41 46 return apiHtml != null; 42 47 } 48 49 /** 50 * 標準の集合操作を返却します。<br/> 51 * {@link java.util.ArrayList}にaddしていく。 52 * 53 * @param <E> 集めるEntity 54 * @return 指定したEntityのArrayListによる集合操作 55 * @since v1.1.0 56 */ 57 static <E extends Entity<E>> CollectOp<E, List<E>> createCollectOp() { 58 return new CollectOp<E, List<E>>(new ArrayList<E>()); 59 } 60 43 61 } -
lang/java/misc/hatenahaiku4j/branches/for-HTML-scraping/src/hatenahaiku4j/HatenaHaikuAPI.java
r35713 r36080 127 127 */ 128 128 public List<Status> getFriendsTimeline(int page, int count, Date since) throws HatenaHaikuException { 129 return getFriendsTimeline( this.<Status>createCollectOp(), page, count, since);129 return getFriendsTimeline(EntityAPI.<Status>createCollectOp(), page, count, since); 130 130 } 131 131 … … 218 218 */ 219 219 public List<Status> getUserTimeline(int page, int count, Date since) throws HatenaHaikuException { 220 return getUserTimeline( this.<Status>createCollectOp(), page, count, since);220 return getUserTimeline(EntityAPI.<Status>createCollectOp(), page, count, since); 221 221 } 222 222 … … 293 293 */ 294 294 public List<Status> getHotUserTimeline(int page, int count, Date since) throws HatenaHaikuException { 295 return getHotUserTimeline( this.<Status>createCollectOp(), page, count, since);295 return getHotUserTimeline(EntityAPI.<Status>createCollectOp(), page, count, since); 296 296 } 297 297 … … 732 732 */ 733 733 public List<User> getFollowingList(int page) throws HatenaHaikuException { 734 return getFollowingList( this.<User>createCollectOp(), page);734 return getFollowingList(EntityAPI.<User>createCollectOp(), page); 735 735 } 736 736 … … 775 775 */ 776 776 public List<User> getFollowersList() throws HatenaHaikuException { 777 return getFollowersList( this.<User>createCollectOp());777 return getFollowersList(EntityAPI.<User>createCollectOp()); 778 778 } 779 779 … … 886 886 */ 887 887 public List<Keyword> getFollowingKeywordList() throws HatenaHaikuException { 888 return getFollowingKeywordList( this.<Keyword>createCollectOp());888 return getFollowingKeywordList(EntityAPI.<Keyword>createCollectOp()); 889 889 } 890 890 -
lang/java/misc/hatenahaiku4j/branches/for-HTML-scraping/src/hatenahaiku4j/HatenaHaikuAPIHTML.java
r36079 r36080 1 1 package hatenahaiku4j; 2 2 3 import hatenahaiku4j.op.CollectOp;4 3 import hatenahaiku4j.op.ReduceOp; 5 import hatenahaiku4j.util.DateUtil;6 4 import hatenahaiku4j.util.HatenaUtil; 7 5 import hatenahaiku4j.util.HttpUtil; … … 123 121 */ 124 122 public List<Status> getPublicTimeline(int page) throws HatenaHaikuException { 125 return getPublicTimeline( this.<Status>createCollectOp(), page);123 return getPublicTimeline(EntityAPI.<Status>createCollectOp(), page); 126 124 } 127 125 … … 242 240 */ 243 241 public List<Status> getFriendsTimeline(String userId, int page) throws HatenaHaikuException { 244 return getFriendsTimeline( this.<Status>createCollectOp(), userId, page);242 return getFriendsTimeline(EntityAPI.<Status>createCollectOp(), userId, page); 245 243 } 246 244 … … 302 300 */ 303 301 public List<Status> getUserTimeline(String userId, int page) throws HatenaHaikuException { 304 return getUserTimeline( this.<Status>createCollectOp(), userId, page);302 return getUserTimeline(EntityAPI.<Status>createCollectOp(), userId, page); 305 303 } 306 304 … … 344 342 */ 345 343 public List<Status> getHotUserTimeline(String userId, int page) throws HatenaHaikuException { 346 return getHotUserTimeline( this.<Status>createCollectOp(), userId, page);344 return getHotUserTimeline(EntityAPI.<Status>createCollectOp(), userId, page); 347 345 } 348 346 … … 402 400 /** 403 401 * 指定したユーザのidページのタイムラインを取得します。最新ページを20件取得します。<br/> 404 * このタイムラインは "id:xxxx" のキーワードタイムラインと同じものです。 405 * 406 * @see HatenaHaikuAPIHTML#getKeywordTimeline(String) 402 * <i>http://h.hatena.ne.jp/target.body?word=id:【ID】&page=【ページ数】</i> 403 * 407 404 * @param userId ユーザID 408 405 * @return 指定したユーザのidページのタイムライン … … 416 413 /** 417 414 * 指定したユーザのidページのタイムラインを取得します。取得件数は20件です。<br/> 418 * このタイムラインは "id:xxxx" のキーワードタイムラインと同じものです。 419 * 420 * @see HatenaHaikuAPIHTML#getKeywordTimeline(String, int) 415 * <i>http://h.hatena.ne.jp/target.body?word=id:【ID】&page=【ページ数】</i> 416 * 421 417 * @param userId ユーザID 422 418 * @param page 取得するページです。 … … 426 422 */ 427 423 public List<Status> getIdTimeline(String userId, int page) throws HatenaHaikuException { 428 return getIdTimeline( this.<Status>createCollectOp(), userId, page);424 return getIdTimeline(EntityAPI.<Status>createCollectOp(), userId, page); 429 425 } 430 426 431 427 /** 432 428 * 指定したユーザのidページのタイムラインを取得します。取得件数は20件です。<br/> 433 * このタイムラインは "id:xxxx" のキーワードタイムラインと同じものです。 434 * 435 * @see HatenaHaikuAPIHTML#getKeywordTimeline(ReduceOp, String, int) 429 * <i>http://h.hatena.ne.jp/target.body?word=id:【ID】&page=【ページ数】</i> 430 * 436 431 * @param op 集合操作 437 432 * @param userId ユーザID … … 445 440 } 446 441 442 // TODO #getHotIdTimelineはAPI版の方には要らないのか?? 443 /** 444 * 指定したユーザのidページの人気のタイムラインを取得します。最新ページを20件取得します。<br/> 445 * <i>http://h.hatena.ne.jp/target.body?mode=hot&word=id:【ID】&page=【ページ数】</i> 446 * 447 * @param userId ユーザID 448 * @return 指定したユーザのidページの人気のタイムライン 449 * @throws HatenaHaikuException 450 * @since v1.2.0 451 */ 452 public List<Status> getHotIdTimeline(String userId) throws HatenaHaikuException { 453 return getHotIdTimeline(userId, 0); 454 } 455 456 /** 457 * 指定したユーザのidページの人気のタイムラインを取得します。取得件数は20件です。<br/> 458 * <i>http://h.hatena.ne.jp/target.body?mode=hot&word=id:【ID】&page=【ページ数】</i> 459 * 460 * @param userId ユーザID 461 * @param page 取得するページです。 462 * @return 指定したユーザのidページの人気のタイムライン 463 * @throws HatenaHaikuException 464 * @since v1.2.0 465 */ 466 public List<Status> getHotIdTimeline(String userId, int page) throws HatenaHaikuException { 467 return getHotIdTimeline(EntityAPI.<Status>createCollectOp(), userId, page); 468 } 469 470 /** 471 * 指定したユーザのidページの人気のタイムラインを取得します。取得件数は20件です。<br/> 472 * <i>http://h.hatena.ne.jp/target.body?mode=hot&word=id:【ID】&page=【ページ数】</i> 473 * 474 * @param op 集合操作 475 * @param userId ユーザID 476 * @param page 取得するページです。 477 * @return 指定したユーザのidページの人気のタイムライン 478 * @throws HatenaHaikuException 479 * @since v1.2.0 480 */ 481 public <T> T getHotIdTimeline(ReduceOp<Status, T> op, String userId, int page) throws HatenaHaikuException { 482 return _getKeywordTimeline(op, userId, page, KeywordTimelineMode.HOT_ID); 483 } 484 447 485 /** 448 486 * 指定したキーワードのキーワードタイムラインを取得します。最新ページを20件取得します。<br/> … … 455 493 */ 456 494 public List<Status> getKeywordTimeline(String keyword) throws HatenaHaikuException { 495 /* 496 * HTML版ではIDタイムラインと、キーワードタイムラインでリクエストURLの形式が 497 * 異なるため、キーワードがid形式だった場合は、#getIdTimelineに処理を移譲する。 498 */ 499 if (HatenaUtil.isIdNotation(keyword)) { 500 return getIdTimeline(keyword.replaceFirst("^" + Const.ID_COLON, "")); 501 } 457 502 return getKeywordTimeline(keyword, 0); 458 503 } … … 469 514 */ 470 515 public List<Status> getKeywordTimeline(String keyword, int page) throws HatenaHaikuException { 471 return getKeywordTimeline(this.<Status>createCollectOp(), keyword, page); 516 /* 517 * HTML版ではIDタイムラインと、キーワードタイムラインでリクエストURLの形式が 518 * 異なるため、キーワードがid形式だった場合は、#getIdTimelineに処理を移譲する。 519 */ 520 if (HatenaUtil.isIdNotation(keyword)) { 521 return getIdTimeline(keyword.replaceFirst("^" + Const.ID_COLON, ""), page); 522 } 523 return getKeywordTimeline(EntityAPI.<Status>createCollectOp(), keyword, page); 472 524 } 473 525 … … 484 536 */ 485 537 public <T> T getKeywordTimeline(ReduceOp<Status, T> op, String keyword, int page) throws HatenaHaikuException { 538 /* 539 * HTML版ではIDタイムラインと、キーワードタイムラインでリクエストURLの形式が 540 * 異なるため、キーワードがid形式だった場合は、#getIdTimelineに処理を移譲する。 541 */ 542 if (HatenaUtil.isIdNotation(keyword)) { 543 return getIdTimeline(op, keyword.replaceFirst("^" + Const.ID_COLON, ""), page); 544 } 486 545 return _getKeywordTimeline(op, keyword, page, KeywordTimelineMode.NONE); 487 546 } … … 497 556 */ 498 557 public List<Status> getHotKeywordTimeline(String keyword) throws HatenaHaikuException { 558 /* 559 * HTML版ではIDタイムラインと、キーワードタイムラインでリクエストURLの形式が 560 * 異なるため、キーワードがid形式だった場合は、#getIdTimelineに処理を移譲する。 561 */ 562 if (HatenaUtil.isIdNotation(keyword)) { 563 return getHotIdTimeline(keyword.replaceFirst("^" + Const.ID_COLON, "")); 564 } 499 565 return getHotKeywordTimeline(keyword, 0); 500 566 } … … 511 577 */ 512 578 public List<Status> getHotKeywordTimeline(String keyword, int page) throws HatenaHaikuException { 513 return getHotKeywordTimeline(this.<Status>createCollectOp(), keyword, page); 579 /* 580 * HTML版ではIDタイムラインと、キーワードタイムラインでリクエストURLの形式が 581 * 異なるため、キーワードがid形式だった場合は、#getIdTimelineに処理を移譲する。 582 */ 583 if (HatenaUtil.isIdNotation(keyword)) { 584 return getHotIdTimeline(keyword.replaceFirst("^" + Const.ID_COLON, ""), page); 585 } 586 return getHotKeywordTimeline(EntityAPI.<Status>createCollectOp(), keyword, page); 514 587 } 515 588 … … 526 599 */ 527 600 public <T> T getHotKeywordTimeline(ReduceOp<Status, T> op, String keyword, int page) throws HatenaHaikuException { 601 /* 602 * HTML版ではIDタイムラインと、キーワードタイムラインでリクエストURLの形式が 603 * 異なるため、キーワードがid形式だった場合は、#getIdTimelineに処理を移譲する。 604 */ 605 if (HatenaUtil.isIdNotation(keyword)) { 606 return getHotIdTimeline(op, keyword.replaceFirst("^" + Const.ID_COLON, ""), page); 607 } 528 608 return _getKeywordTimeline(op, keyword, page, KeywordTimelineMode.HOT); 529 609 } … … 553 633 */ 554 634 public List<Status> getAlbumKeywordTimeline(String keyword, int page) throws HatenaHaikuException { 555 return getAlbumKeywordTimeline( this.<Status>createCollectOp(), keyword, page);635 return getAlbumKeywordTimeline(EntityAPI.<Status>createCollectOp(), keyword, page); 556 636 } 557 637 … … 676 756 */ 677 757 public List<Keyword> getHotKeywordList() throws HatenaHaikuException { 678 return getHotKeywordList( this.<Keyword>createCollectOp());758 return getHotKeywordList(EntityAPI.<Keyword>createCollectOp()); 679 759 } 680 760 … … 773 853 */ 774 854 public List<Keyword> getKeywordList(String searchWord, int page) throws HatenaHaikuException { 775 return getKeywordList( this.<Keyword>createCollectOp(), searchWord, page);855 return getKeywordList(EntityAPI.<Keyword>createCollectOp(), searchWord, page); 776 856 } 777 857 … … 1009 1089 } 1010 1090 1011 /** 1012 * ユーザエレメントをUser情報に変換します。 1013 * 1014 * @param elemUser ユーザエレメント 1015 * @return User情報 1016 * @since v1.2.0 1017 */ 1018 protected User toUser(Element elemUser) { 1019 User user = createUser(); 1020 // ユーザ名 1021 user.setName(XmlUtil.getText(elemUser, "name")); 1022 // フォロワー数 1023 user.setFollowersCount(Integer.parseInt(XmlUtil.getText(elemUser, "followers_count"))); 1024 // ユーザID 1025 user.setUserId(XmlUtil.getText(elemUser, "id")); 1026 // プロフィール画像URL 1027 user.setProfileImageUrl(XmlUtil.getText(elemUser, "profile_image_url")); 1028 // 表示名 1029 user.setScreenName(XmlUtil.getText(elemUser, "screen_name")); 1030 // ユーザのエントリページのURL 1031 user.setUrl(XmlUtil.getText(elemUser, "url")); 1032 return user; 1033 } 1034 1035 /** 1036 * ユーザエレメントルートをUser情報リストに変換します。 1037 * 1038 * @param op 集合操作 1039 * @param elemUsers ユーザエレメントルート 1040 * @return User情報リスト 1041 * @since v1.2.0 1042 */ 1043 protected <T> T toUserList(ReduceOp<User, T> op, Element elemUsers) throws HatenaHaikuException { 1044 for (Element elemUser : XmlUtil.getChildElementsByTagName(elemUsers, "user")) { 1045 op.add(toUser(elemUser)); 1046 } 1047 return op.value(); 1048 } 1091 // TODO 今のところユーザを取得するメソッドは作成していない 1092 // /** 1093 // * ユーザエレメントをUser情報に変換します。 1094 // * 1095 // * @param elemUser ユーザエレメント 1096 // * @return User情報 1097 // * @since v1.2.0 1098 // */ 1099 // protected User toUser(Element elemUser) { 1100 // User user = createUser(); 1101 // // ユーザ名 1102 // user.setName(XmlUtil.getText(elemUser, "name")); 1103 // // フォロワー数 1104 // user.setFollowersCount(Integer.parseInt(XmlUtil.getText(elemUser, "followers_count"))); 1105 // // ユーザID 1106 // user.setUserId(XmlUtil.getText(elemUser, "id")); 1107 // // プロフィール画像URL 1108 // user.setProfileImageUrl(XmlUtil.getText(elemUser, "profile_image_url")); 1109 // // 表示名 1110 // user.setScreenName(XmlUtil.getText(elemUser, "screen_name")); 1111 // // ユーザのエントリページのURL 1112 // user.setUrl(XmlUtil.getText(elemUser, "url")); 1113 // return user; 1114 // } 1115 1116 // TODO 今のところユーザを取得するメソッドは作成していない 1117 // /** 1118 // * ユーザエレメントルートをUser情報リストに変換します。 1119 // * 1120 // * @param op 集合操作 1121 // * @param elemUsers ユーザエレメントルート 1122 // * @return User情報リスト 1123 // * @since v1.2.0 1124 // */ 1125 // protected <T> T toUserList(ReduceOp<User, T> op, Element elemUsers) throws HatenaHaikuException { 1126 // for (Element elemUser : XmlUtil.getChildElementsByTagName(elemUsers, "user")) { 1127 // op.add(toUser(elemUser)); 1128 // } 1129 // return op.value(); 1130 // } 1049 1131 1050 1132 /** … … 1113 1195 1114 1196 /** 1115 * 標準の集合操作を返却します。<br/>1116 * {@link java.util.ArrayList}にaddしていく。1117 *1118 * @param <E> 集めるEntity1119 * @return 指定したEntityのArrayListによる集合操作1120 * @since v1.2.01121 */1122 protected <E extends Entity<E>> CollectOp<E, List<E>> createCollectOp() {1123 return new CollectOp<E, List<E>>(new ArrayList<E>());1124 }1125 1126 /**1127 1197 * キーワードタイムライン取得モード 1128 1198 * … … 1146 1216 /** 1147 1217 * ステータスリスト 1218 * @see HatenaHaikuAPIHTML#getPublicTimeline() 1219 * @see HatenaHaikuAPIHTML#getFriendsTimeline() 1220 * @see HatenaHaikuAPIHTML#_getUserTimeline() 1221 * @see HatenaHaikuAPIHTML#_getKeywordTimeline() 1148 1222 */ 1149 1223 STATUS_LIST, -
lang/java/misc/hatenahaiku4j/branches/for-HTML-scraping/src/hatenahaiku4j/HatenaHaikuAPILight.java
r36056 r36080 1 1 package hatenahaiku4j; 2 2 3 import hatenahaiku4j.op.CollectOp;4 3 import hatenahaiku4j.op.ReduceOp; 5 4 import hatenahaiku4j.util.DateUtil; … … 177 176 */ 178 177 public List<Status> getPublicTimeline(int page, Date since) throws HatenaHaikuException { 179 return getPublicTimeline( this.<Status>createCollectOp(), page, since);178 return getPublicTimeline(EntityAPI.<Status>createCollectOp(), page, since); 180 179 } 181 180 … … 271 270 */ 272 271 public List<Status> getFriendsTimeline(String userId, int page, int count, Date since) throws HatenaHaikuException { 273 return getFriendsTimeline( this.<Status>createCollectOp(), userId, page, count, since);272 return getFriendsTimeline(EntityAPI.<Status>createCollectOp(), userId, page, count, since); 274 273 } 275 274 … … 367 366 */ 368 367 public List<Status> getUserTimeline(String userId, int page, int count, Date since) throws HatenaHaikuException { 369 return getUserTimeline( this.<Status>createCollectOp(), userId, page, count, since);368 return getUserTimeline(EntityAPI.<Status>createCollectOp(), userId, page, count, since); 370 369 } 371 370 … … 447 446 */ 448 447 public List<Status> getHotUserTimeline(String userId, int page, int count, Date since) throws HatenaHaikuException { 449 return getHotUserTimeline( this.<Status>createCollectOp(), userId, page, count, since);448 return getHotUserTimeline(EntityAPI.<Status>createCollectOp(), userId, page, count, since); 450 449 } 451 450 … … 565 564 */ 566 565 public List<Status> getIdTimeline(String userId, int page, int count, Date since) throws HatenaHaikuException { 567 return getIdTimeline( this.<Status>createCollectOp(), userId, page, count, since);566 return getIdTimeline(EntityAPI.<Status>createCollectOp(), userId, page, count, since); 568 567 } 569 568 … … 645 644 */ 646 645 public List<Status> getKeywordTimeline(String keyword, int page, int count, Date since) throws HatenaHaikuException { 647 return getKeywordTimeline( this.<Status>createCollectOp(), keyword, page, count, since);646 return getKeywordTimeline(EntityAPI.<Status>createCollectOp(), keyword, page, count, since); 648 647 } 649 648 … … 725 724 */ 726 725 public List<Status> getHotKeywordTimeline(String keyword, int page, int count, Date since) throws HatenaHaikuException { 727 return getHotKeywordTimeline( this.<Status>createCollectOp(), keyword, page, count, since);726 return getHotKeywordTimeline(EntityAPI.<Status>createCollectOp(), keyword, page, count, since); 728 727 } 729 728 … … 839 838 */ 840 839 public List<Status> getAlbumTimeline(int page, int count, Date since) throws HatenaHaikuException { 841 return getAlbumTimeline( this.<Status>createCollectOp(), page, count, since);840 return getAlbumTimeline(EntityAPI.<Status>createCollectOp(), page, count, since); 842 841 } 843 842 … … 934 933 */ 935 934 public List<Status> getAlbumKeywordTimeline(String keyword, int page, int count, Date since) throws HatenaHaikuException { 936 return getAlbumKeywordTimeline( this.<Status>createCollectOp(), keyword, page, count, since);935 return getAlbumKeywordTimeline(EntityAPI.<Status>createCollectOp(), keyword, page, count, since); 937 936 } 938 937 … … 1035 1034 */ 1036 1035 public List<User> getFollowingList(String userId, int page) throws HatenaHaikuException { 1037 return getFollowingList( this.<User>createCollectOp(), userId, page);1036 return getFollowingList(EntityAPI.<User>createCollectOp(), userId, page); 1038 1037 } 1039 1038 … … 1080 1079 */ 1081 1080 public List<User> getFollowersList(String userId) throws HatenaHaikuException { 1082 return getFollowersList( this.<User>createCollectOp(), userId);1081 return getFollowersList(EntityAPI.<User>createCollectOp(), userId); 1083 1082 } 1084 1083 … … 1152 1151 */ 1153 1152 public List<Keyword> getHotKeywordList() throws HatenaHaikuException { 1154 return getHotKeywordList( this.<Keyword>createCollectOp());1153 return getHotKeywordList(EntityAPI.<Keyword>createCollectOp()); 1155 1154 } 1156 1155 … … 1225 1224 */ 1226 1225 public List<Keyword> getKeywordList(String searchWord, int page) throws HatenaHaikuException { 1227 return getKeywordList( this.<Keyword>createCollectOp(), searchWord, page);1226 return getKeywordList(EntityAPI.<Keyword>createCollectOp(), searchWord, page); 1228 1227 } 1229 1228 … … 1272 1271 */ 1273 1272 public List<Keyword> getFollowingKeywordList(String userId) throws HatenaHaikuException { 1274 return getFollowingKeywordList( this.<Keyword>createCollectOp(), userId);1273 return getFollowingKeywordList(EntityAPI.<Keyword>createCollectOp(), userId); 1275 1274 } 1276 1275 … … 1504 1503 } 1505 1504 1506 /**1507 * 標準の集合操作を返却します。<br/>1508 * {@link java.util.ArrayList}にaddしていく。1509 *1510 * @param <E> 集めるEntity1511 * @return 指定したEntityのArrayListによる集合操作1512 * @since v1.1.01513 */1514 protected <E extends Entity<E>> CollectOp<E, List<E>> createCollectOp() {1515 return new CollectOp<E, List<E>>(new ArrayList<E>());1516 }1517 1518 1505 } -
lang/java/misc/hatenahaiku4j/branches/for-HTML-scraping/src/hatenahaiku4j/sample/Sample001.java
r35715 r36080 89 89 sb.append(HatenaUtil.formatDate(status.getCreatedAt())); 90 90 sb.append("〔☆×").append(status.getFavorited()).append("〕"); 91 sb.append(status.getText());92 91 if (!StringUtil.isEmpty(status.getInReplyToStatusId())) { 93 sb.append(" reply to ").append(status.getInReplyToUserId()); 92 sb.append(" @").append(status.getInReplyToUserId()) 93 .append("(").append(status.getInReplyToStatusId()).append(")"); 94 94 } 95 sb.append(" ").append(status.getText()); 95 96 sb.append(" by ").append(status.getUserId()); 96 97 sb.append(" from ").append(status.getSource()); … … 102 103 } 103 104 replies.append(reply.getUserId()); 105 replies.append("(").append(reply.getStatusId()).append(")"); 104 106 } 105 107 sb.append(" replied from ").append(replies);
![(please configure the [header_logo] section in trac.ini)](/share/chrome/site/your_project_logo.png)