Changeset 443
- Timestamp:
- 08/13/06 00:26:28 (2 years ago)
- Files:
-
- 1.7.7/CHANGES.177 (modified) (1 diff)
- 1.7.7/COPYRITE (modified) (1 diff)
- 1.7.7/Configure (modified) (6 diffs)
- 1.7.7/Patchlevel (modified) (1 diff)
- 1.7.7/config_h.SH (modified) (2 diffs)
- 1.7.7/game/txt/hlp/pennv177.hlp (modified) (2 diffs)
- 1.7.7/game/txt/hlp/pennvOLD.hlp (modified) (1 diff)
- 1.7.7/hdrs/copyrite.h (modified) (1 diff)
- 1.7.7/hdrs/externs.h (modified) (1 diff)
- 1.7.7/hdrs/mysocket.h (modified) (1 diff)
- 1.7.7/hdrs/version.h (modified) (1 diff)
- 1.7.7/src/bsd.c (modified) (3 diffs)
- 1.7.7/src/look.c (modified) (1 diff)
- 1.7.7/src/move.c (modified) (1 diff)
- 1.7.7/src/mysocket.c (modified) (2 diffs)
- 1.7.7/src/predicat.c (modified) (1 diff)
- 1.7.7/src/set.c (modified) (5 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
1.7.7/CHANGES.177
r441 r443 18 18 19 19 ========================================================================== 20 21 Version 1.7.7 patchlevel 22 September 30, 2003 22 23 Minor Changes: 24 * When possible, sockets are now set SO_KEEPALIVE and TCP_KEEPIDLE. 25 This may help prevent disconnections of idle players behind 26 poorly designed NAT routers and the like, and make the use of 27 the IDLE command unnecessary. Patch by Philip Mak. 28 * Better failure messages for 'get blah's blah', especially when 29 the container or contained object is ambiguous. Suggested by 30 Philip Mak. 31 Fixes: 32 * Attempting to unset attribute flags actually set them. 33 Report by Ambrosia@M*U*S*H. [SW] 34 * Remove a warning in set.c. Report by Nymeria@M*U*S*H 35 20 36 21 37 Version 1.7.7 patchlevel 21 September 23, 2003 1.7.7/COPYRITE
r399 r443 42 42 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 43 43 * 44 * Although not necessary given the above copyright, the TinyMUSH 2.0 45 * developers, Joseph Traub and Glenn Crocker, confirmed in email to 46 * Alan Schwartz in 2002 that they were willing to have any of their 47 * code present in PennMUSH redistributed under the Artistic License. 48 * 44 49 * The portions derived from TinyMUSH 2.2 are used under the Artistic 45 * License. The Artistic License is also the license under which you 46 * are granted permission to copy and modify PennMUSH: 50 * License. Jean Marie Diaz, Lydia Leong, and Devin Hooker, the 51 * TinyMUSH 2.2 copyright holders, explicitly agreed to relicense 52 * their source code under the Artistic License in 2002, and TinyMUSH 2.2.5 53 * was released under this license; Alan Schwartz has confirmatory email 54 * from them authorizing the redistribution of any portions of TinyMUSH 2.2 55 * that may be present in PennMUSH under the Artistic License. 56 * 57 * The Artistic License is also the license under which you 58 * are granted permission to copy, modify, and redistribute PennMUSH: 47 59 * 48 60 * The Artistic License 1.7.7/Configure
r439 r443 367 367 i_niin='' 368 368 i_sysin='' 369 i_nitcp='' 369 370 i_setjmp='' 370 371 i_stddef='' … … 440 441 sizetype='' 441 442 so='' 443 d_keepalive='' 444 d_keepidle='' 442 445 sharpbang='' 443 446 shsharp='' … … 4521 4524 eval $inlibc 4522 4525 4526 socketlib='' 4527 sockethdr='' 4528 : see whether socket exists 4529 echo " " 4530 $echo $n "Hmm... $c" >&4 4531 if set socket val -f d_socket; eval $csym; $val; then 4532 echo "Looks like you have Berkeley networking support." >&4 4533 d_socket="$define" 4534 if set setsockopt val -f; eval $csym; $val; then 4535 d_oldsock="$undef" 4536 else 4537 echo "...but it uses the old 4.1c interface, rather than 4.2" >&4 4538 d_oldsock="$define" 4539 fi 4540 else 4541 if $contains socklib libc.list >/dev/null 2>&1; then 4542 echo "Looks like you have Berkeley networking support." >&4 4543 d_socket="$define" 4544 : we will have to assume that it supports the 4.2 BSD interface 4545 d_oldsock="$undef" 4546 else 4547 echo "You don't have Berkeley networking in libc$_a..." >&4 4548 if test -f /usr/lib/libnet$_a; then 4549 ( (nm $nm_opt /usr/lib/libnet$_a | eval $nm_extract) || \ 4550 ar t /usr/lib/libnet$_a) 2>/dev/null >> libc.list 4551 if $contains socket libc.list >/dev/null 2>&1; then 4552 echo "...but the Wollongong group seems to have hacked it in." >&4 4553 socketlib="-lnet" 4554 sockethdr="-I/usr/netinclude" 4555 d_socket="$define" 4556 if $contains setsockopt libc.list >/dev/null 2>&1; then 4557 d_oldsock="$undef" 4558 else 4559 echo "...using the old 4.1c interface, rather than 4.2" >&4 4560 d_oldsock="$define" 4561 fi 4562 else 4563 echo "or even in libnet$_a, which is peculiar." >&4 4564 d_socket="$undef" 4565 d_oldsock="$undef" 4566 fi 4567 else 4568 echo "or anywhere else I see." >&4 4569 d_socket="$undef" 4570 d_oldsock="$undef" 4571 fi 4572 fi 4573 fi 4574 4575 : see if socketpair exists 4576 set socketpair d_sockpair 4577 eval $inlibc 4578 4579 : see if this is a netinet/tcp.h system 4580 set netinet/tcp.h i_nitcp 4581 eval $inhdr 4582 4583 : see if setsockopt with SO_KEEPALIVE works as advertised 4584 echo " " 4585 case "$d_oldsock" in 4586 "$undef") 4587 echo "OK, let's see if SO_KEEPALIVE works as advertised..." >&4 4588 $cat > socket.c <<EOP 4589 #include <sys/types.h> 4590 #include <sys/socket.h> 4591 #include <netinet/in.h> 4592 #$i_nitcp I_NETINET_TCP 4593 #ifdef I_NETINET_TCP 4594 #include <netinet/tcp.h> 4595 #endif 4596 #include <netdb.h> 4597 4598 main() 4599 { 4600 int s = socket(AF_INET, SOCK_STREAM, 0); 4601 int val = 1; 4602 if (s == -1) 4603 exit(1); 4604 if (-1 == setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val))) 4605 exit(2); 4606 #ifdef I_NETINET_TCP 4607 val = 1; 4608 if (-1 == setsockopt(s, IPPROTO_TCP, TCP_KEEPIDLE, &val, sizeof(val))) 4609 exit(3); 4610 #endif 4611 exit(0); 4612 } 4613 EOP 4614 if $cc $ccflags $sockethdr socket.c -o socket $libs \ 4615 $socketlib >/dev/null 2>&1; then 4616 ./socket >/dev/null 2>&1 4617 case $? in 4618 0) echo "Yes, it does!" 4619 val="$define" 4620 val2="$i_nitcp" 4621 ;; 4622 1) $cat <<EOM 4623 (Something went wrong -- Assuming SO_KEEPALIVE is broken) 4624 EOM 4625 val="$undef" 4626 val2="$undef" 4627 ;; 4628 2) echo "No, it doesn't. Don't trust your manuals!!" 4629 val="$undef" 4630 val2="$undef" 4631 ;; 4632 3) echo "It does, but TCP_KEEPIDLE doesn't." 4633 val="$define" 4634 val2="$undef" 4635 ;; 4636 esac 4637 else 4638 cat <<EOM 4639 (I can't compile the test program -- Assuming SO_KEEPALIVE is broken) 4640 EOM 4641 val="$undef" 4642 val2="$undef" 4643 fi 4644 ;; 4645 *) cat <<EOM 4646 As you have an old socket interface, you can't have heard of SO_KEEPALIVE. 4647 EOM 4648 val="$undef" 4649 val2="$undef";; 4650 esac 4651 set d_keepalive 4652 eval $setvar 4653 val="$val2" 4654 set d_keepidle 4655 eval $setvar 4656 $rm -f socket socket.c 4657 4523 4658 echo " " 4524 4659 : see if we have sigaction … … 4964 5099 set d_snprintf 4965 5100 eval $setvar 4966 4967 socketlib=''4968 sockethdr=''4969 : see whether socket exists4970 echo " "4971 $echo $n "Hmm... $c" >&44972 if set socket val -f d_socket; eval $csym; $val; then4973 echo "Looks like you have Berkeley networking support." >&44974 d_socket="$define"4975 if set setsockopt val -f; eval $csym; $val; then4976 d_oldsock="$undef"4977 else4978 echo "...but it uses the old 4.1c interface, rather than 4.2" >&44979 d_oldsock="$define"4980 fi4981 else4982 if $contains socklib libc.list >/dev/null 2>&1; then4983 echo "Looks like you have Berkeley networking support." >&44984 d_socket="$define"4985 : we will have to assume that it supports the 4.2 BSD interface4986 d_oldsock="$undef"4987 else4988 echo "You don't have Berkeley networking in libc$_a..." >&44989 if test -f /usr/lib/libnet$_a; then4990 ( (nm $nm_opt /usr/lib/libnet$_a | eval $nm_extract) || \4991 ar t /usr/lib/libnet$_a) 2>/dev/null >> libc.list4992 if $contains socket libc.list >/dev/null 2>&1; then4993 echo "...but the Wollongong group seems to have hacked it in." >&44994 socketlib="-lnet"4995 sockethdr="-I/usr/netinclude"4996 d_socket="$define"4997 if $contains setsockopt libc.list >/dev/null 2>&1; then4998 d_oldsock="$undef"4999 else5000 echo "...using the old 4.1c interface, rather than 4.2" >&45001 d_oldsock="$define"5002 fi5003 else5004 echo "or even in libnet$_a, which is peculiar." >&45005 d_socket="$undef"5006 d_oldsock="$undef"5007 fi5008 else5009 echo "or anywhere else I see." >&45010 d_socket="$undef"5011 d_oldsock="$undef"5012 fi5013 fi5014 fi5015 5016 : see if socketpair exists5017 set socketpair d_sockpair5018 eval $inlibc5019 5101 5020 5102 : see if we have socklen_t. … … 6792 6874 d_ipv6='$d_ipv6' 6793 6875 d_itimer='$d_itimer' 6876 d_keepalive='$d_keepalive' 6877 d_keepidle='$d_keepidle' 6794 6878 d_keepsig='$d_keepsig' 6795 6879 d_lrand48='$d_lrand48' … … 6884 6968 i_netdb='$i_netdb' 6885 6969 i_niin='$i_niin' 6970 i_nitcp='$i_nitcp' 6886 6971 i_setjmp='$i_setjmp' 6887 6972 i_sgtty='$i_sgtty' 1.7.7/Patchlevel
r441 r443 1 1 Do not edit this file. It is maintained by the official PennMUSH patches. 2 This is PennMUSH 1.7.7p2 12 This is PennMUSH 1.7.7p22 1.7.7/config_h.SH
r425 r443 787 787 #$i_netdb I_NETDB /**/ 788 788 789 /* I_NETINET_TCP: 790 * This symbol, if defined, indicates to the C program that it should 791 * include <netinet/tcp.h>. 792 */ 793 #$i_nitcp I_NETINET_TCP /**/ 794 789 795 /* I_SETJMP: 790 796 * This symbol, if defined, indicates to the C program that it can … … 824 830 #$d_openssl HAS_OPENSSL /**/ 825 831 832 /* CAN_KEEPALIVE: 833 * This symbol if defined indicates to the C program that the SO_KEEPALIVE 834 * option of setsockopt() will work as advertised in the manual. 835 */ 836 /* CAN_KEEPIDLE: 837 * This symbol if defined indicates to the C program that the TCP_KEEPIDLE 838 * option of setsockopt() will work as advertised in the manual. 839 */ 840 #$d_keepalive CAN_KEEPALIVE /**/ 841 842 #$d_keepidle CAN_KEEPIDLE /**/ 843 826 844 #endif 827 845 !GROK!THIS! 1.7.7/game/txt/hlp/pennv177.hlp
r441 r443 1 & 1.7.7p2 11 & 1.7.7p22 2 2 & changes 3 3 This is a list of changes in this patchlevel which are probably of … … 12 12 be read in 'help patchlevels'. 13 13 14 Version 1.7.7 patchlevel 22 September 30, 2003 15 16 Minor Changes: 17 * When possible, sockets are now set SO_KEEPALIVE and TCP_KEEPIDLE. 18 This may help prevent disconnections of idle players behind 19 poorly designed NAT routers and the like, and make the use of 20 the IDLE command unnecessary. Patch by Philip Mak. 21 * Better failure messages for 'get blah's blah', especially when 22 the container or contained object is ambiguous. Suggested by 23 Philip Mak. 24 Fixes: 25 * Attempting to unset attribute flags actually set them. 26 Report by Ambrosia@M*U*S*H. [SW] 27 * Remove a warning in set.c. Report by Nymeria@M*U*S*H 28 29 30 & 1.7.7p21 14 31 Version 1.7.7 patchlevel 21 September 23, 2003 15 32 1.7.7/game/txt/hlp/pennvOLD.hlp
r441 r443 4419 4419 4420 4420 1.7.7: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 4421 19, 20, 21 4421 19, 20, 21, 22 4422 4422 1.7.6: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 4423 4423 1.7.5: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 1.7.7/hdrs/copyrite.h
r399 r443 42 42 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 43 43 * 44 * Although not necessary given the above copyright, the TinyMUSH 2.0 45 * developers, Joseph Traub and Glenn Crocker, confirmed in email to 46 * Alan Schwartz in 2002 that they were willing to have any of their 47 * code present in PennMUSH redistributed under the Artistic License. 48 * 44 49 * The portions derived from TinyMUSH 2.2 are used under the Artistic 45 * License. The Artistic License is also the license under which you 46 * are granted permission to copy and modify PennMUSH: 50 * License. Jean Marie Diaz, Lydia Leong, and Devin Hooker, the 51 * TinyMUSH 2.2 copyright holders, explicitly agreed to relicense 52 * their source code under the Artistic License in 2002, and TinyMUSH 2.2.5 53 * was released under this license; Alan Schwartz has confirmatory email 54 * from them authorizing the redistribution of any portions of TinyMUSH 2.2 55 * that may be present in PennMUSH under the Artistic License. 56 * 57 * The Artistic License is also the license under which you 58 * are granted permission to copy, modify, and redistribute PennMUSH: 47 59 * 48 60 * The Artistic License 1.7.7/hdrs/externs.h
r441 r443 273 273 extern int ok_player_name(const char *name, dbref player); 274 274 extern int ok_password(const char *password); 275 extern dbref parse_match_possess ive(dbref player, const char*str);275 extern dbref parse_match_possessor(dbref player, const char **str); 276 276 extern void page_return(dbref player, dbref target, const char *type, 277 277 const char *message, const char *def); 1.7.7/hdrs/mysocket.h
r427 r443 70 70 socklen_t myilen, Port_t port, int *timeout); 71 71 void make_nonblocking(int s); 72 void set_keepalive(int s); 72 73 int connect_nonb 73 74 (int sockfd, const struct sockaddr *saptr, socklen_t salen, int *nsec); 1.7.7/hdrs/version.h
r441 r443 1 #define VERSION "PennMUSH version 1.7.7 patchlevel 2 1 [09/23/2003]"2 #define SHORTVN "PennMUSH 1.7.7p2 1"3 #define NUMVERSION 00100700702 11 #define VERSION "PennMUSH version 1.7.7 patchlevel 22 [09/30/2003]" 2 #define SHORTVN "PennMUSH 1.7.7p22" 3 #define NUMVERSION 001007007022 1.7.7/src/bsd.c
r441 r443 134 134 #endif 135 135 #endif 136 136 137 137 138 /* BSD 4.2 and maybe some others need these defined */ … … 1321 1322 do_log(LT_CONN, 0, 0, T("[%d/%s/%s] Connection opened."), newsock, tbuf1, 1322 1323 tbuf2); 1324 set_keepalive(newsock); 1323 1325 return initializesock(newsock, tbuf1, tbuf2, use_ssl); 1324 1326 } … … 2098 2100 do_log(LT_CONN, 0, 0, T("[%d/%s/%s] Connection opened."), fd, 2099 2101 bp ? bp : "", buf); 2102 set_keepalive(fd); 2100 2103 (void) initializesock(fd, bp ? bp : buf, buf, (atoi(bp2) == SSLPORT)); 2101 2104 } 1.7.7/src/look.c
r441 r443 610 610 /* look at a thing in location */ 611 611 if ((thing = match_result(player, name, NOTYPE, MAT_NEARBY)) == NOTHING) { 612 thing = parse_match_possessive(player, name); 613 if (!GoodObject(thing)) { 612 dbref box; 613 const char *boxname = name; 614 box = parse_match_possessor(player, &name); 615 if (box == NOTHING) { 614 616 notify(player, T("I don't see that here.")); 617 return; 618 } else if (box == AMBIGUOUS) { 619 notify_format(player, T("I can't tell which %s."), boxname); 620 return; 621 } 622 thing = match_result(box, name, NOTYPE, MAT_POSSESSION); 623 if (thing == NOTHING) { 624 notify(player, T("I don't see that here.")); 625 return; 626 } else if (thing == AMBIGUOUS) { 627 notify_format(player, T("I can't tell which %s."), name); 615 628 return; 616 629 } 1.7.7/src/move.c
r441 r443 525 525 if (match_result(player, what, TYPE_THING, match_flags) == NOTHING) { 526 526 if (POSSESSIVE_GET) { 527 dbref box; 528 const char *boxname = what; 527 529 /* take care of possessive get (stealing) */ 528 thing = parse_match_possessive(player,what);529 if ( !GoodObject(thing)) {530 box = parse_match_possessor(player, &what); 531 if (box == NOTHING) { 530 532 notify(player, T("I don't see that here.")); 533 return; 534 } else if (box == AMBIGUOUS) { 535 notify_format(player, T("I can't tell which %s."), boxname); 536 return; 537 } 538 thing = match_result(box, what, NOTYPE, MAT_POSSESSION); 539 if (thing == NOTHING) { 540 notify(player, T("I don't see that here.")); 541 return; 542 } else if (thing == AMBIGUOUS) { 543 notify_format(player, T("I can't tell which %s."), what); 531 544 return; 532 545 } 1.7.7/src/mysocket.c
r429 r443 32 32 #include <sys/in.h> 33 33 #endif 34 #endif 35 36 #ifdef I_NETINET_TCP 37 #include <netinet/tcp.h> 34 38 #endif 35 39 … … 357 361 #endif /* !macintosh */ 358 362 } 363 364 365 366 /* Enable TCP keepalive on the given socket if we can */ 367 void 368 set_keepalive(int s) 369 { 370 #ifdef CAN_KEEPALIVE 371 int keepalive = 1; 372 #ifdef CAN_KEEPIDLE 373 int keepidle = 900; 374 #endif 375 376 /* enable TCP keepalive */ 377 if (setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, 378 (void *) &keepalive, sizeof(keepalive)) == -1) 379 fprintf(stderr, "[%d] could not set SO_KEEPALIVE: errno %d", s, errno); 380 #ifdef CAN_KEEPIDLE 381 if (setsockopt(s, IPPROTO_TCP, TCP_KEEPIDLE, 382 (void *) &keepidle, sizeof(keepidle)) == -1) 383 fprintf(stderr, "[%d] could not set TCP_KEEPALIVE: errno %d", s, errno); 384 #endif 385 #endif 386 return; 387 } 388 389 359 390 360 391 /** Connect a socket, possibly making it nonblocking first. 1.7.7/src/predicat.c
r441 r443 840 840 } 841 841 842 /** Parse possessive matches .842 /** Parse possessive matches for the possessor. 843 843 * This function parses strings of the form "Sam's bag" and attempts 844 * to match "bag" in the contents of "Sam". It returns NOTHING if 845 * there's no possessive 's in the string. 844 * to match "Sam". It returns NOTHING if 845 * there's no possessive 's in the string. It destructively modifies 846 * the string (terminating after the possessor name) and modifies the pointer 847 * to the string to point at the name of the contained object. 846 848 * \param player the enactor/looker. 847 * \param str a string to check for possessive matches.848 * \return matching dbref or NOTHING .849 * \param str a pointer to a string to check for possessive matches. 850 * \return matching dbref or NOTHING or AMBIGUOUS. 849 851 */ 850 852 dbref 851 parse_match_possess ive(dbref player, const char*str)852 { 853 c har *box;/* name of container */853 parse_match_possessor(dbref player, const char **str) 854 { 855 const char *box; /* name of container */ 854 856 char *obj; /* name of object */ 855 dbref loc; /* dbref of container */ 856 char name[BUFFER_LEN]; /* str would be destructively modified */ 857 858 strcpy(name, str); 859 box = name; 857 858 box = *str; 860 859 861 860 /* check to see if we have an 's sequence */ 862 if ((obj = strchr( name, '\'')) == NULL)861 if ((obj = strchr(box, '\'')) == NULL) 863 862 return NOTHING; 864 863 *obj++ = '\0'; /* terminate */ 865 864 if ((*obj == '\0') || ((*obj != 's') && (*obj != 'S'))) 866 865 return NOTHING; 867 868 866 /* skip over the 's' and whitespace */ 869 867 do { 870 868 obj++; 871 869 } while (isspace((unsigned char) *obj)); 870 *str = obj; 872 871 873 872 /* we already have a terminating null, so we're okay to just do matches */ 874 loc = match_result(player, box, NOTYPE, MAT_NEIGHBOR | MAT_POSSESSION); 875 if (!GoodObject(loc)) 876 return NOTHING; 877 878 /* now we match on the contents */ 879 return (match_result(loc, obj, NOTYPE, MAT_POSSESSION)); 873 return match_result(player, box, NOTYPE, MAT_NEIGHBOR | MAT_POSSESSION); 880 874 } 881 875 1.7.7/src/set.c
r441 r443 459 459 struct af_args { 460 460 int f; /**< flag bits */ 461 char const *flag; /**< flag name */ 461 int clear; /**< True to remove the flag */ 462 char *flag; /**< flag name */ 462 463 }; 463 464 … … 474 475 */ 475 476 if (!(Can_Write_Attr(player, thing, AL_ATTR(atr)) || 476 ( (*af->flag == NOT_TOKEN)&& (af->f == AF_SAFE) &&477 (af->clear && (af->f == AF_SAFE) && 477 478 Can_Write_Attr_Ignore_Safe(player, thing, AL_ATTR(atr))))) { 478 479 notify_format(player, T("You cannot change that flag on %s/%s"), … … 481 482 } 482 483 483 if ( *af->flag == NOT_TOKEN) {484 if (af->clear) { 484 485 AL_FLAGS(atr) &= ~af->f; 485 486 if (!AreQuiet(player, thing)) 486 487 notify_format(player, T("%s/%s - %s reset."), Name(thing), AL_NAME(atr), 487 (af->flag + 1));488 af->flag); 488 489 } else { 489 490 AL_FLAGS(atr) |= af->f; … … 531 532 return; 532 533 } 534 535 af.clear = 0; 536 533 537 /* move past NOT token if there is one */ 534 for (p = flag; *p && ((*p == NOT_TOKEN) || isspace((unsigned char) *p)); 535 p++) ; 538 for (p = flag; *p && ((*p == NOT_TOKEN) || isspace((unsigned char) *p)); p++) 539 if (*p == NOT_TOKEN) 540 af.clear = !af.clear; 536 541 537 542 if ((af.f = string_to_atrflag(player, p)) < 0) { … … 542 547 if (!atr_iter_get(player, thing, atrname, 0, af_helper, &af)) 543 548 notify(player, T("No attribute found to change.")); 544 mush_free( af.flag, "af_flag list");549 mush_free((Malloc_t) af.flag, "af_flag list"); 545 550 } 546 551
