TapatalkClient.java (20778B)
1 package de.mtbnews.android.tapatalk; 2 3 import java.util.ArrayList; 4 import java.util.Date; 5 import java.util.List; 6 import java.util.Map; 7 8 import org.xmlrpc.android.XMLRPCClient; 9 import org.xmlrpc.android.XMLRPCException; 10 11 import android.text.TextUtils; 12 import de.mtbnews.android.tapatalk.TapatalkException.TapatalkErrorCode; 13 import de.mtbnews.android.tapatalk.wrapper.Forum; 14 import de.mtbnews.android.tapatalk.wrapper.ListHolder; 15 import de.mtbnews.android.tapatalk.wrapper.Mailbox; 16 import de.mtbnews.android.tapatalk.wrapper.Message; 17 import de.mtbnews.android.tapatalk.wrapper.Post; 18 import de.mtbnews.android.tapatalk.wrapper.Search; 19 import de.mtbnews.android.tapatalk.wrapper.Topic; 20 21 /** 22 * Tapatalk-compatible client. 23 * 24 * @author Jan Dankert 25 * 26 */ 27 public class TapatalkClient 28 { 29 private XMLRPCClient client; 30 31 public boolean loggedIn; 32 public long loginTime; 33 34 /** 35 * @param connectorUrl 36 * URL 37 */ 38 public TapatalkClient(String connectorUrl) 39 { 40 this.client = new XMLRPCClient(connectorUrl); 41 } 42 43 /** 44 * Benutzer-Login. Falls Login nicht klappt, wird eine 45 * {@link TapatalkException} geworfen. 46 * 47 * @param username 48 * @param password 49 * @throws TapatalkException 50 */ 51 public void login(String username, String password) throws TapatalkException 52 { 53 this.loggedIn = false; 54 this.loginTime = -1L; 55 56 if (TextUtils.isEmpty(username)) 57 throw new TapatalkException("Username empty", TapatalkErrorCode.NO_USERNAME); 58 59 final Object[] params = new Object[] { username.getBytes(), password.getBytes() }; 60 61 try 62 { 63 64 toMap(client.callEx("login", params)); 65 this.loggedIn = true; 66 this.loginTime = System.currentTimeMillis(); 67 } 68 catch (XMLRPCException e) 69 { 70 throw new TapatalkException("Login failed" + ": " + e.getMessage(), e, TapatalkErrorCode.XMLRPC_ERROR); 71 } 72 73 } 74 75 public void logout() throws TapatalkException 76 { 77 78 try 79 { 80 @SuppressWarnings("unused") 81 Object result = client.call("logout_user"); 82 this.loggedIn = false; 83 } 84 catch (XMLRPCException e) 85 { 86 throw new TapatalkException("Logout failed" + ": " + e.getMessage(), e, TapatalkErrorCode.XMLRPC_ERROR); 87 } 88 } 89 90 /** 91 * Load a topic. 92 * 93 * @param topicId 94 * topic-id 95 * @param start 96 * start-position 97 * @param end 98 * end-position 99 * @return list of topics 100 * @throws TapatalkException 101 */ 102 @SuppressWarnings("unchecked") 103 public Topic getTopic(String topicId, int start, int end) throws TapatalkException 104 { 105 try 106 { 107 Object[] params = new Object[] { topicId, start, end }; 108 109 Map map = toMap(client.callEx("get_thread", params)); 110 111 String title = byteArrayToString(map.get("topic_title")); 112 String id = (String) map.get("topic_id"); 113 int postCount = toInt(map.get("total_post_num")); 114 115 List<Post> posts = new ArrayList<Post>(); 116 Topic topic = new Topic(id, posts, title, null, null, null, postCount); 117 topic.forumId = (String) map.get("forum_id"); 118 119 for (Object o1 : (Object[]) map.get("posts")) 120 { 121 Map postMap = (Map) o1; 122 Post post = new Post((Date) postMap.get("post_time"), byteArrayToString(postMap.get("post_title")), 123 byteArrayToString(postMap.get("post_content")), byteArrayToString(postMap 124 .get("post_author_name"))); 125 posts.add(post); 126 } 127 128 return topic; 129 } 130 catch (XMLRPCException e) 131 { 132 throw new TapatalkException("Could not load Topic " + topicId, e, TapatalkErrorCode.XMLRPC_ERROR); 133 } 134 } 135 136 public List<Forum> getAllForum() throws TapatalkException 137 { 138 try 139 { 140 Object l = client.call("get_forum"); 141 Object[] arr = (Object[]) l; 142 Map[] mapArr = castToMapArray(arr); 143 144 List<Forum> forum = createSubForen(mapArr, "child"); 145 146 return forum; 147 } 148 catch (XMLRPCException e) 149 { 150 throw new TapatalkException("Could not load Forum structure", e, TapatalkErrorCode.XMLRPC_ERROR); 151 } 152 } 153 154 private Map[] castToMapArray(Object[] arr) 155 { 156 Map[] mapArr = new Map[arr.length]; 157 int i = 0; 158 for (Object object : arr) 159 { 160 mapArr[i] = (Map) arr[i++]; 161 } 162 return mapArr; 163 } 164 165 public final static int TOPIC_STANDARD = 1; 166 public final static int TOPIC_STICKY = 2; 167 public final static int TOPIC_ANNOUNCEMENT = 3; 168 169 @SuppressWarnings("unchecked") 170 public Forum getForum(String forumId, int from, int to, int mode) throws TapatalkException 171 { 172 try 173 { 174 final String mode2; 175 176 if (mode == TOPIC_ANNOUNCEMENT) 177 mode2 = "ANN"; 178 else if (mode == TOPIC_STICKY) 179 mode2 = "TOP"; 180 else 181 mode2 = ""; 182 183 final Object[] params = new Object[] { forumId, from, to, mode2 }; 184 Map map = (Map) toMap(client.callEx("get_topic", params)); 185 186 final List<Topic> topics = new ArrayList<Topic>(); 187 final List<Post> posts = new ArrayList<Post>(); 188 189 String title = byteArrayToString(map.get("forum_name")); 190 String id = (String) map.get("forum_id"); 191 192 final Forum forum = new Forum(id, topics, title, null, null); 193 forum.topicCount = (Integer) map.get("total_topic_num"); 194 195 if (forum.topicCount > 0) 196 { 197 for (Object o1 : (Object[]) map.get("topics")) 198 { 199 Map topicMap = (Map) o1; 200 Topic topic = new Topic((String) topicMap.get("topic_id"), posts, // 201 byteArrayToString(topicMap.get("topic_title")),// 202 (Date) topicMap.get("last_reply_time"), // 203 byteArrayToString(topicMap.get("short_content")),// 204 byteArrayToString(topicMap.get("topic_author_name")), 0); 205 topic.unread = toBool(topicMap.get("new_post")); 206 topics.add(topic); 207 } 208 } 209 210 return forum; 211 } 212 catch (XMLRPCException e) 213 { 214 throw new TapatalkException("Could not load Forum " + forumId + ": " + e.getMessage(), e, 215 TapatalkErrorCode.XMLRPC_ERROR); 216 } 217 } 218 219 @SuppressWarnings("unchecked") 220 public ListHolder<Topic> getSubscribedTopics(int from, int to, boolean onlyUnread) throws TapatalkException 221 { 222 try 223 { 224 final Object[] params = new Object[] { from, to }; 225 Map map = toMap(client.callEx("get_subscribed_topic", params)); 226 227 int topicCount = (Integer) map.get("total_topic_num"); 228 229 final List<Topic> topics = new ArrayList<Topic>(); 230 231 for (Object o1 : (Object[]) map.get("topics")) 232 { 233 Map topicMap = (Map) o1; 234 if (!onlyUnread || (Boolean) topicMap.get("new_post")) 235 { 236 237 Topic topic = new Topic((String) topicMap.get("topic_id"), new ArrayList<Post>(), // 238 byteArrayToString(topicMap.get("topic_title")),// 239 (Date) topicMap.get("post_time"), // 240 byteArrayToString(topicMap.get("short_content")),// 241 byteArrayToString(topicMap.get("post_author_name")), 0); 242 topic.unread = (Boolean) topicMap.get("new_post"); 243 topics.add(topic); 244 } 245 } 246 247 ListHolder<Topic> topicHolder = new ListHolder<Topic>(topics, topicCount, from, to); 248 return topicHolder; 249 } 250 catch (XMLRPCException e) 251 { 252 throw new TapatalkException("Could not load subscribe topics" + ": " + e.getMessage(), e, 253 TapatalkErrorCode.XMLRPC_ERROR); 254 } 255 } 256 257 @SuppressWarnings("unchecked") 258 public List<Forum> getSubscribedForum(boolean onlyUnread) throws TapatalkException 259 { 260 try 261 { 262 Map map = toMap(client.call("get_subscribed_forum")); 263 264 @SuppressWarnings("unused") 265 int forumCount = (Integer) map.get("total_forums_num"); 266 267 final List<Forum> forums = new ArrayList<Forum>(); 268 269 for (Object o1 : (Object[]) map.get("forums")) 270 { 271 Map map2 = (Map) o1; 272 if (!onlyUnread || (Boolean) map2.get("new_post")) 273 { 274 String id = (String) map2.get("forum_id"); 275 String name = byteArrayToString(map2.get("forum_name")); 276 Forum forum = new Forum(id, new ArrayList<Topic>(), name, null, null); 277 forum.unread = (Boolean) map2.get("new_post"); 278 279 forums.add(forum); 280 } 281 } 282 283 return forums; 284 } 285 catch (XMLRPCException e) 286 { 287 throw new TapatalkException("Could not load subscribe topics" + ": " + e.getMessage(), e, 288 TapatalkErrorCode.XMLRPC_ERROR); 289 } 290 } 291 292 /** 293 * Mark a forum as read 294 * 295 * @param forumId 296 * if <code>null</code>, all forums are marked read 297 * @throws TapatalkException 298 */ 299 public void markForumAsRead(String forumId) throws TapatalkException 300 { 301 try 302 { 303 if (forumId == null) 304 { 305 toMap(client.call("mark_all_as_read")); 306 } 307 else 308 { 309 Object[] params = new Object[] { forumId }; 310 toMap(client.callEx("mark_all_as_read", params)); 311 } 312 313 } 314 catch (XMLRPCException e) 315 { 316 throw new TapatalkException("XMLRPC-Error: " + e.getMessage(), e, TapatalkErrorCode.XMLRPC_ERROR); 317 } 318 } 319 320 /** 321 * Mark a forum as read 322 * 323 * @param topicId 324 * @throws TapatalkException 325 */ 326 public void markTopicAsRead(String topicId) throws TapatalkException 327 { 328 try 329 { 330 // Object param = new String[] { topicId }; 331 // toMap(client.call("mark_topic_read", param)); 332 Object[] params = new String[] { topicId }; 333 toMap(client.callEx("mark_topic_read", params)); 334 335 } 336 catch (XMLRPCException e) 337 { 338 throw new TapatalkException("Marking topics read: " + e.getMessage(), e, TapatalkErrorCode.XMLRPC_ERROR); 339 } 340 } 341 342 public final static int SUBSCRIBE_NONE = -1; 343 public final static int SUBSCRIBE_WITHOUT_EMAIL = 0; 344 public final static int SUBSCRIBE_INSTANT_EMAIL = 1; 345 public final static int SUBSCRIBE_DAILY_EMAIL = 2; 346 public final static int SUBSCRIBE_WEEKLY_EMAIL = 3; 347 348 /** 349 * Subscribes to a forum. 350 * 351 * @param forumId 352 * The forum-Id 353 * @param mode 354 * One of the SUBSCRIBE_*-constants 355 * @throws TapatalkException 356 */ 357 public void subscribeForum(String forumId, int mode) throws TapatalkException 358 { 359 try 360 { 361 if (mode == SUBSCRIBE_NONE) 362 { 363 Object[] params = new Object[] { forumId }; 364 toMap(client.callEx("unsubscribe_forum", params)); 365 } 366 else 367 { 368 Object[] params = new Object[] { forumId, mode }; 369 toMap(client.callEx("subscribe_forum", params)); 370 } 371 372 } 373 catch (XMLRPCException e) 374 { 375 throw new TapatalkException("Could not load subscribe topics" + ": " + e.getMessage(), e, 376 TapatalkErrorCode.XMLRPC_ERROR); 377 } 378 } 379 380 /** 381 * Subscribes to a topic. 382 * 383 * @param topicId 384 * The topic-id 385 * @param mode 386 * One of the SUBSCRIBE_*-constants 387 * @throws TapatalkException 388 */ 389 public void subscribeTopic(String topicId, int mode) throws TapatalkException 390 { 391 try 392 { 393 if (mode == SUBSCRIBE_NONE) 394 { 395 Object[] params = new Object[] { topicId }; 396 toMap(client.callEx("unsubscribe_topic", params)); 397 } 398 else 399 { 400 Object[] params = new Object[] { topicId, mode }; 401 toMap(client.callEx("subscribe_topic", params)); 402 } 403 404 } 405 catch (XMLRPCException e) 406 { 407 throw new TapatalkException("Could not load subscribe topics" + ": " + e.getMessage(), e, 408 TapatalkErrorCode.XMLRPC_ERROR); 409 } 410 } 411 412 public static final int SEARCHTYPE_QUERY = 1; 413 public static final int SEARCHTYPE_LATEST = 2; 414 public static final int SEARCHTYPE_PARTICIPATED = 3; 415 public static final int SEARCHTYPE_UNREAD = 4; 416 417 public Search searchTopics(int searchType, String query, String username, int start, int end, String searchId) 418 throws TapatalkException 419 { 420 try 421 { 422 Object[] params = null; 423 String method = null; 424 425 switch (searchType) 426 { 427 case SEARCHTYPE_QUERY: 428 method = "search_topic"; 429 if (searchId == null) 430 params = new Object[] { query.getBytes(), start, end }; 431 else 432 params = new Object[] { "".getBytes(), start, end, searchId }; 433 break; 434 case SEARCHTYPE_LATEST: 435 method = "get_latest_topic"; 436 if (searchId == null) 437 params = new Object[] { start, end }; 438 else 439 params = new Object[] { start, end, searchId }; 440 break; 441 case SEARCHTYPE_PARTICIPATED: 442 method = "get_participated_topic"; 443 if (searchId == null) 444 params = new Object[] { username.getBytes(), start, end }; 445 else 446 params = new Object[] { username.getBytes(), start, end, searchId }; 447 break; 448 case SEARCHTYPE_UNREAD: 449 method = "get_unread_topic"; 450 if (searchId == null) 451 params = new Object[] { start, end }; 452 else 453 params = new Object[] { start, end, searchId }; 454 break; 455 } 456 457 Map map = toMap(client.callEx(method, params)); 458 459 Integer topicCount = (Integer) map.get("total_topic_num"); 460 String newSearchId = (String) map.get("search_id"); 461 final List<Topic> topics = new ArrayList<Topic>(); 462 Search search = new Search(topicCount, newSearchId, topics); 463 464 final List<Post> posts = new ArrayList<Post>(); 465 466 for (Object o1 : (Object[]) map.get("topics")) 467 { 468 Map topicMap = toMap(o1); 469 Topic topic = new Topic((String) topicMap.get("topic_id"), posts, // 470 byteArrayToString(topicMap.get("topic_title")),// 471 (Date) topicMap.get("post_time"), // 472 byteArrayToString(topicMap.get("short_content")),// 473 byteArrayToString(topicMap.get("post_author_name")), 0); 474 topic.unread = toBool( topicMap.get("new_post") ); 475 topics.add(topic); 476 } 477 478 return search; 479 } 480 catch (XMLRPCException e) 481 { 482 throw new TapatalkException("Could not search" + ": " + e.getMessage(), e, TapatalkErrorCode.XMLRPC_ERROR); 483 } 484 } 485 486 /** 487 * Reads the list of all available mailboxes. 488 * 489 * @param boxId 490 * @param start 491 * @param end 492 * @return 493 * @throws TapatalkException 494 */ 495 public List<Mailbox> getMailbox() throws TapatalkException 496 { 497 try 498 { 499 Map map = toMap(client.call("get_box_info")); 500 501 final List<Mailbox> boxList = new ArrayList<Mailbox>(); 502 503 for (Object o1 : (Object[]) map.get("list")) 504 { 505 Map mapMap = toMap(o1); 506 Mailbox box = new Mailbox((String) mapMap.get("box_id"), byteArrayToString(mapMap.get("box_name")),// 507 (Integer) mapMap.get("msg_count"), // 508 (Integer) mapMap.get("unread_count")); 509 boxList.add(box); 510 box.messages = new ArrayList<Message>(); 511 } 512 513 return boxList; 514 } 515 catch (XMLRPCException e) 516 { 517 throw new TapatalkException("Could not read mailbox" + ": " + e.getMessage(), e, 518 TapatalkErrorCode.XMLRPC_ERROR); 519 } 520 } 521 522 /** 523 * Gets all messsages in a box. 524 * 525 * @param boxId 526 * @param start 527 * @param end 528 * @return 529 * @throws TapatalkException 530 */ 531 public Mailbox getBoxContent(String boxId, int start, int end) throws TapatalkException 532 { 533 try 534 { 535 Object[] params = new Object[] { boxId, start, end }; 536 Map map = toMap(client.callEx("get_box", params)); 537 538 Mailbox mailbox = new Mailbox(boxId, "", (Integer) map.get("total_message_count"), (Integer) map 539 .get("total_unread_count")); 540 541 final List<Message> messageList = new ArrayList<Message>(); 542 mailbox.messages = messageList; 543 544 for (Object o1 : (Object[]) map.get("list")) 545 { 546 Map msgMap = toMap(o1); 547 548 Object[] objects = (Object[]) msgMap.get("msg_to"); 549 String[] msgTo = new String[objects.length]; 550 for (int j = 0; j < objects.length; j++) 551 msgTo[j] = byteArrayToString((toMap(objects[j]).get("username"))); 552 553 Message message = new Message((String) msgMap.get("msg_id"), ((Integer) msgMap.get("msg_state")) 554 .equals(1), // 555 (Date) msgMap.get("sent_date"),// 556 byteArrayToString(msgMap.get("msg_from")),// 557 msgTo,// 558 byteArrayToString(msgMap.get("msg_subject")), // 559 byteArrayToString(msgMap.get("short_content"))); 560 messageList.add(message); 561 } 562 563 return mailbox; 564 } 565 catch (XMLRPCException e) 566 { 567 throw new TapatalkException("Could not read mailbox " + boxId + ": " + e.getMessage(), e, 568 TapatalkErrorCode.XMLRPC_ERROR); 569 } 570 } 571 572 /** 573 * Reads a message 574 * 575 * @param boxId 576 * @param messageId 577 * @param asHtml 578 * @return 579 * @throws TapatalkException 580 */ 581 public Message getMessage(String boxId, String messageId) throws TapatalkException 582 { 583 try 584 { 585 final Object[] params = new Object[] { messageId, boxId }; 586 587 Map<String, Object> mapMap = toMap(client.callEx("get_message", params)); 588 589 Object[] objects = (Object[]) mapMap.get("msg_to"); 590 String[] msgTo = new String[objects.length]; 591 for (int j = 0; j < objects.length; j++) 592 msgTo[j] = byteArrayToString((toMap(objects[j]).get("username"))); 593 594 Message message = new Message(messageId, false, // 595 (Date) mapMap.get("sent_date"),// 596 byteArrayToString(mapMap.get("msg_from")),// 597 msgTo,// 598 byteArrayToString(mapMap.get("msg_subject")), // 599 byteArrayToString(mapMap.get("text_body"))); 600 return message; 601 602 } 603 catch (XMLRPCException e) 604 { 605 throw new TapatalkException("Could not read message " + boxId + "," + messageId + ": " + e.getMessage(), e, 606 TapatalkErrorCode.XMLRPC_ERROR); 607 } 608 } 609 610 /** 611 * Create a topic 612 * 613 * @param forumId 614 * @param subject 615 * @param content 616 * @throws TapatalkException 617 */ 618 public void createTopic(String forumId, String subject, String content) throws TapatalkException 619 { 620 try 621 { 622 final Object[] params = new Object[] { forumId, subject.getBytes(), content.getBytes() }; 623 624 Map<?, ?> map = toMap(client.callEx("new_topic", params)); 625 626 @SuppressWarnings("unused") 627 // the newly generated post ID for this new topic. 628 String msgId = (String) map.get("post_id"); 629 } 630 catch (XMLRPCException e) 631 { 632 throw new TapatalkException("Could not create the topic: " + e.getMessage(), e, 633 TapatalkErrorCode.XMLRPC_ERROR); 634 } 635 } 636 637 /** 638 * Create a post. 639 * 640 * @param boxId 641 * @param messageId 642 * @param asHtml 643 * @return 644 * @throws TapatalkException 645 */ 646 public void createReply(String forumId, String topicId, String subject, String content) throws TapatalkException 647 { 648 try 649 { 650 final Object[] params = new Object[] { forumId, topicId, subject.getBytes(), content.getBytes() }; 651 652 Map<?, ?> map = toMap(client.callEx("reply_post", params)); 653 654 @SuppressWarnings("unused") 655 String msgId = (String) map.get("topic_id"); 656 } 657 catch (XMLRPCException e) 658 { 659 throw new TapatalkException("Could not reply", e, TapatalkErrorCode.XMLRPC_ERROR); 660 } 661 } 662 663 /** 664 * Create a message. 665 * 666 * @param boxId 667 * @param messageId 668 * @param asHtml 669 * @return 670 * @throws TapatalkException 671 */ 672 public void createMessage(String[] to, String subject, String content) throws TapatalkException 673 { 674 try 675 { 676 final Object[] params = new Object[] { to, subject.getBytes(), content.getBytes() }; 677 678 Object result = client.callEx("create_message", params); 679 680 if (result instanceof Boolean) 681 { 682 // Im Erfolgsfall ist das result vom Typ java.lang.Boolean 683 684 final Boolean ok = (Boolean) result; 685 if (!ok) 686 { 687 throw new TapatalkException("sending message failed", TapatalkErrorCode.SEND_MESSAGE_FAILED); 688 } 689 } 690 else 691 { 692 // Das result kann auch eine Map sein 693 694 try 695 { 696 toMap(result); 697 } 698 catch (TapatalkException e) 699 { 700 throw new TapatalkException("sending message failed: " + e.getMessage(), 701 TapatalkErrorCode.SEND_MESSAGE_FAILED); 702 } 703 } 704 } 705 catch (XMLRPCException e) 706 { 707 throw new TapatalkException("Could not create the message", e, TapatalkErrorCode.XMLRPC_ERROR); 708 } 709 } 710 711 public void setUserAgent(String agent) 712 { 713 client.setUserAgent(agent); 714 } 715 716 private static String byteArrayToString(Object object) 717 { 718 byte[] byteArray = (byte[]) object; 719 if (byteArray == null) 720 return null; 721 else 722 return new String(byteArray); 723 } 724 725 private static int toInt(Object object) 726 { 727 Integer i = (Integer) object; 728 if (i == null) 729 return 0; 730 else 731 return i.intValue(); 732 } 733 734 private static boolean toBool(Object object) 735 { 736 if (object == null) 737 return false; 738 else 739 return (Boolean) object; 740 } 741 742 /** 743 * Converting the object to a map. If object is no Map, it throws a 744 * {@link TapatalkException}. If Map contains a key "result" and the value 745 * is not 'true', a {@link TapatalkException} is thrown. 746 * 747 * @param o 748 * @return 749 * @throws TapatalkException 750 */ 751 @SuppressWarnings("unchecked") 752 private Map<String, Object> toMap(Object o) throws TapatalkException 753 { 754 if (!(o instanceof Map)) 755 { 756 throw new TapatalkException("no map: " + o.toString() + " (" + o.getClass() + ")", 757 TapatalkErrorCode.UNKNOWN_SERVER_RESPONSE); 758 } 759 Map<String, Object> map = (Map<String, Object>) o; 760 761 Object object = map.get("result"); 762 if (object == null) 763 return map; 764 765 boolean ok = (Boolean) object; 766 if (!ok) 767 throw new TapatalkException(byteArrayToString(map.get("result_text")), 768 TapatalkErrorCode.UNKNOWN_SERVER_RESPONSE); 769 return map; 770 } 771 772 private List<Forum> createSubForen(Map[] mapArray, String childName) 773 { 774 775 final List<Forum> list = new ArrayList<Forum>(); 776 777 for (Map map : mapArray) 778 { 779 String name = byteArrayToString(map.get("forum_name")); 780 String content = byteArrayToString(map.get("description")); 781 String id = (String) map.get("forum_id"); 782 Forum forum = new Forum(id, new ArrayList<Topic>(), name, null, content); 783 forum.url = (String) map.get("url"); 784 list.add(forum); 785 forum.subOnly = (Boolean) map.get("sub_only"); 786 if (map.containsKey(childName)) 787 forum.subForen = createSubForen(castToMapArray((Object[]) map.get(childName)), childName); 788 } 789 return list; 790 791 } 792 }