comparison input/input.c @ 16856:d222ea8f2cb4

translatable eng strings to new section on help_mp-en
author reynaldo
date Tue, 25 Oct 2005 18:46:25 +0000
parents 8d4fb5469efb
children a68ede010f66
comparison
equal deleted inserted replaced
16855:5f83daf94eb2 16856:d222ea8f2cb4
18 #include <assert.h> 18 #include <assert.h>
19 #endif 19 #endif
20 #include "../osdep/getch2.h" 20 #include "../osdep/getch2.h"
21 #include "../osdep/keycodes.h" 21 #include "../osdep/keycodes.h"
22 #include "../osdep/timer.h" 22 #include "../osdep/timer.h"
23 #include "../mp_msg.h" 23 #include "mp_msg.h"
24 #include "../help_mp.h" 24 #include "help_mp.h"
25 #include "../m_config.h" 25 #include "../m_config.h"
26 #include "../m_option.h" 26 #include "../m_option.h"
27 27
28 #include "joystick.h" 28 #include "joystick.h"
29 29
468 468
469 469
470 int 470 int
471 mp_input_add_cmd_fd(int fd, int select, mp_cmd_func_t read_func, mp_close_func_t close_func) { 471 mp_input_add_cmd_fd(int fd, int select, mp_cmd_func_t read_func, mp_close_func_t close_func) {
472 if(num_cmd_fd == MP_MAX_CMD_FD) { 472 if(num_cmd_fd == MP_MAX_CMD_FD) {
473 mp_msg(MSGT_INPUT,MSGL_ERR,"Too many command fds, unable to register fd %d.\n",fd); 473 mp_msg(MSGT_INPUT,MSGL_ERR,MSGTR_INPUT_INPUT_ErrCantRegister2ManyCmdFds,fd);
474 return 0; 474 return 0;
475 } 475 }
476 476
477 memset(&cmd_fds[num_cmd_fd],0,sizeof(mp_input_fd_t)); 477 memset(&cmd_fds[num_cmd_fd],0,sizeof(mp_input_fd_t));
478 cmd_fds[num_cmd_fd].fd = fd; 478 cmd_fds[num_cmd_fd].fd = fd;
524 } 524 }
525 525
526 int 526 int
527 mp_input_add_key_fd(int fd, int select, mp_key_func_t read_func, mp_close_func_t close_func) { 527 mp_input_add_key_fd(int fd, int select, mp_key_func_t read_func, mp_close_func_t close_func) {
528 if(num_key_fd == MP_MAX_KEY_FD) { 528 if(num_key_fd == MP_MAX_KEY_FD) {
529 mp_msg(MSGT_INPUT,MSGL_ERR,"Too many key fds, unable to register fd %d.\n",fd); 529 mp_msg(MSGT_INPUT,MSGL_ERR,MSGTR_INPUT_INPUT_ErrCantRegister2ManyKeyFds,fd);
530 return 0; 530 return 0;
531 } 531 }
532 532
533 memset(&key_fds[num_key_fd],0,sizeof(mp_input_fd_t)); 533 memset(&key_fds[num_key_fd],0,sizeof(mp_input_fd_t));
534 key_fds[num_key_fd].fd = fd; 534 key_fds[num_key_fd].fd = fd;
595 switch(cmd_def->args[i].type) { 595 switch(cmd_def->args[i].type) {
596 case MP_CMD_ARG_INT: 596 case MP_CMD_ARG_INT:
597 errno = 0; 597 errno = 0;
598 cmd->args[i].v.i = atoi(ptr); 598 cmd->args[i].v.i = atoi(ptr);
599 if(errno != 0) { 599 if(errno != 0) {
600 mp_msg(MSGT_INPUT,MSGL_ERR,"Command %s: argument %d isn't an integer.\n",cmd_def->name,i+1); 600 mp_msg(MSGT_INPUT,MSGL_ERR,MSGTR_INPUT_INPUT_ErrArgMustBeInt,cmd_def->name,i+1);
601 ptr = NULL; 601 ptr = NULL;
602 } 602 }
603 break; 603 break;
604 case MP_CMD_ARG_FLOAT: 604 case MP_CMD_ARG_FLOAT:
605 errno = 0; 605 errno = 0;
606 cmd->args[i].v.f = atof(ptr); 606 cmd->args[i].v.f = atof(ptr);
607 if(errno != 0) { 607 if(errno != 0) {
608 mp_msg(MSGT_INPUT,MSGL_ERR,"Command %s: argument %d isn't a float.\n",cmd_def->name,i+1); 608 mp_msg(MSGT_INPUT,MSGL_ERR,MSGTR_INPUT_INPUT_ErrArgMustBeFloat,cmd_def->name,i+1);
609 ptr = NULL; 609 ptr = NULL;
610 } 610 }
611 break; 611 break;
612 case MP_CMD_ARG_STRING: { 612 case MP_CMD_ARG_STRING: {
613 char term; 613 char term;
625 if(e <= ptr2 || *(e - 1) != '\\') break; 625 if(e <= ptr2 || *(e - 1) != '\\') break;
626 ptr2 = e + 1; 626 ptr2 = e + 1;
627 } 627 }
628 628
629 if(term != ' ' && (!e || e[0] == '\0')) { 629 if(term != ' ' && (!e || e[0] == '\0')) {
630 mp_msg(MSGT_INPUT,MSGL_ERR,"Command %s: argument %d is unterminated.\n",cmd_def->name,i+1); 630 mp_msg(MSGT_INPUT,MSGL_ERR,MSGTR_INPUT_INPUT_ErrUnterminatedArg,cmd_def->name,i+1);
631 ptr = NULL; 631 ptr = NULL;
632 break; 632 break;
633 } else if(!e) e = ptr+strlen(ptr); 633 } else if(!e) e = ptr+strlen(ptr);
634 l = e-start; 634 l = e-start;
635 ptr2 = start; 635 ptr2 = start;
645 } break; 645 } break;
646 case -1: 646 case -1:
647 ptr = NULL; 647 ptr = NULL;
648 break; 648 break;
649 default : 649 default :
650 mp_msg(MSGT_INPUT,MSGL_ERR,"Unknown argument %d\n",i); 650 mp_msg(MSGT_INPUT,MSGL_ERR,MSGTR_INPUT_INPUT_ErrUnknownArg,i);
651 } 651 }
652 } 652 }
653 cmd->nargs = i; 653 cmd->nargs = i;
654 654
655 if(cmd_def->nargs > cmd->nargs) { 655 if(cmd_def->nargs > cmd->nargs) {
656 mp_msg(MSGT_INPUT,MSGL_ERR,"Got command '%s' but\n",str); 656 /* mp_msg(MSGT_INPUT,MSGL_ERR,"Got command '%s' but\n",str); */
657 mp_msg(MSGT_INPUT,MSGL_ERR,"command %s requires at least %d arguments, we found only %d so far.\n",cmd_def->name,cmd_def->nargs,cmd->nargs); 657 mp_msg(MSGT_INPUT,MSGL_ERR,MSGTR_INPUT_INPUT_Err2FewArgs,cmd_def->name,cmd_def->nargs,cmd->nargs);
658 mp_cmd_free(cmd); 658 mp_cmd_free(cmd);
659 return NULL; 659 return NULL;
660 } 660 }
661 661
662 for( ; i < MP_CMD_MAX_ARGS && cmd_def->args[i].type != -1 ; i++) { 662 for( ; i < MP_CMD_MAX_ARGS && cmd_def->args[i].type != -1 ; i++) {
705 // Error ? 705 // Error ?
706 if(r < 0) { 706 if(r < 0) {
707 switch(r) { 707 switch(r) {
708 case MP_INPUT_ERROR: 708 case MP_INPUT_ERROR:
709 case MP_INPUT_DEAD: 709 case MP_INPUT_DEAD:
710 mp_msg(MSGT_INPUT,MSGL_ERR,"Error while reading cmd fd %d: %s\n",mp_fd->fd,strerror(errno)); 710 mp_msg(MSGT_INPUT,MSGL_ERR,MSGTR_INPUT_INPUT_ErrReadingCmdFd,mp_fd->fd,strerror(errno));
711 case MP_INPUT_NOTHING: 711 case MP_INPUT_NOTHING:
712 return r; 712 return r;
713 case MP_INPUT_RETRY: 713 case MP_INPUT_RETRY:
714 continue; 714 continue;
715 } 715 }
732 end = strchr(mp_fd->buffer,'\n'); 732 end = strchr(mp_fd->buffer,'\n');
733 // No cmd end ? 733 // No cmd end ?
734 if(!end) { 734 if(!end) {
735 // If buffer is full we must drop all until the next \n 735 // If buffer is full we must drop all until the next \n
736 if(mp_fd->size - mp_fd->pos <= 1) { 736 if(mp_fd->size - mp_fd->pos <= 1) {
737 mp_msg(MSGT_INPUT,MSGL_ERR,"Cmd buffer of fd %d is full: dropping content\n",mp_fd->fd); 737 mp_msg(MSGT_INPUT,MSGL_ERR,MSGTR_INPUT_INPUT_ErrCmdBufferFullDroppingContent,mp_fd->fd);
738 mp_fd->pos = 0; 738 mp_fd->pos = 0;
739 mp_fd->flags |= MP_FD_DROP; 739 mp_fd->flags |= MP_FD_DROP;
740 } 740 }
741 break; 741 break;
742 } 742 }
843 mp_msg(MSGT_INPUT,MSGL_WARN," \n"); 843 mp_msg(MSGT_INPUT,MSGL_WARN," \n");
844 return NULL; 844 return NULL;
845 } 845 }
846 ret = mp_input_parse_cmd(cmd); 846 ret = mp_input_parse_cmd(cmd);
847 if(!ret) { 847 if(!ret) {
848 mp_msg(MSGT_INPUT,MSGL_ERR,"Invalid command for bound key %s",mp_input_get_key_name(key_down[0])); 848 mp_msg(MSGT_INPUT,MSGL_ERR,MSGTR_INPUT_INPUT_ErrInvalidCommandForKey,mp_input_get_key_name(key_down[0]));
849 if( num_key_down > 1) { 849 if( num_key_down > 1) {
850 unsigned int s; 850 unsigned int s;
851 for(s=1; s < num_key_down; s++) 851 for(s=1; s < num_key_down; s++)
852 mp_msg(MSGT_INPUT,MSGL_ERR,"-%s",mp_input_get_key_name(key_down[s])); 852 mp_msg(MSGT_INPUT,MSGL_ERR,"-%s",mp_input_get_key_name(key_down[s]));
853 } 853 }
904 904
905 while(1) { 905 while(1) {
906 if(select(max_fd+1,&fds,NULL,NULL,time_val) < 0) { 906 if(select(max_fd+1,&fds,NULL,NULL,time_val) < 0) {
907 if(errno == EINTR) 907 if(errno == EINTR)
908 continue; 908 continue;
909 mp_msg(MSGT_INPUT,MSGL_ERR,"Select error: %s\n",strerror(errno)); 909 mp_msg(MSGT_INPUT,MSGL_ERR,MSGTR_INPUT_INPUT_ErrSelect,strerror(errno));
910 } 910 }
911 break; 911 break;
912 } 912 }
913 913
914 } 914 }
938 938
939 if(code >= 0) 939 if(code >= 0)
940 return code; 940 return code;
941 941
942 if(code == MP_INPUT_ERROR) 942 if(code == MP_INPUT_ERROR)
943 mp_msg(MSGT_INPUT,MSGL_ERR,"Error on key input fd %d\n",key_fds[i].fd); 943 mp_msg(MSGT_INPUT,MSGL_ERR,MSGTR_INPUT_INPUT_ErrOnKeyInFd,key_fds[i].fd);
944 else if(code == MP_INPUT_DEAD) { 944 else if(code == MP_INPUT_DEAD) {
945 mp_msg(MSGT_INPUT,MSGL_ERR,"Dead key input on fd %d\n",key_fds[i].fd); 945 mp_msg(MSGT_INPUT,MSGL_ERR,MSGTR_INPUT_INPUT_ErrDeadKeyOnFd,key_fds[i].fd);
946 key_fds[i].flags |= MP_FD_DEAD; 946 key_fds[i].flags |= MP_FD_DEAD;
947 } 947 }
948 } 948 }
949 return MP_INPUT_NOTHING; 949 return MP_INPUT_NOTHING;
950 } 950 }
967 967
968 for( ; code >= 0 ; code = mp_input_read_key_code(0) ) { 968 for( ; code >= 0 ; code = mp_input_read_key_code(0) ) {
969 // key pushed 969 // key pushed
970 if(code & MP_KEY_DOWN) { 970 if(code & MP_KEY_DOWN) {
971 if(num_key_down > MP_MAX_KEY_DOWN) { 971 if(num_key_down > MP_MAX_KEY_DOWN) {
972 mp_msg(MSGT_INPUT,MSGL_ERR,"Too many key down events at the same time\n"); 972 mp_msg(MSGT_INPUT,MSGL_ERR,MSGTR_INPUT_INPUT_Err2ManyKeyDowns);
973 continue; 973 continue;
974 } 974 }
975 code &= ~MP_KEY_DOWN; 975 code &= ~MP_KEY_DOWN;
976 // Check if we don't already have this key as pushed 976 // Check if we don't already have this key as pushed
977 for(j = 0; j < num_key_down; j++) { 977 for(j = 0; j < num_key_down; j++) {
993 if(key_down[j] == code) 993 if(key_down[j] == code)
994 break; 994 break;
995 } 995 }
996 if(j == num_key_down) { // key was not in the down keys : add it 996 if(j == num_key_down) { // key was not in the down keys : add it
997 if(num_key_down > MP_MAX_KEY_DOWN) { 997 if(num_key_down > MP_MAX_KEY_DOWN) {
998 mp_msg(MSGT_INPUT,MSGL_ERR,"Too many key down events at the same time\n"); 998 mp_msg(MSGT_INPUT,MSGL_ERR,MSGTR_INPUT_INPUT_Err2ManyKeyDowns);
999 continue; 999 continue;
1000 } 1000 }
1001 key_down[num_key_down] = code; 1001 key_down[num_key_down] = code;
1002 num_key_down++; 1002 num_key_down++;
1003 last_key_down = 1; 1003 last_key_down = 1;
1088 while(n > 0) { 1088 while(n > 0) {
1089 if((i = select(max_fd+1,&fds,NULL,NULL,time_val)) <= 0) { 1089 if((i = select(max_fd+1,&fds,NULL,NULL,time_val)) <= 0) {
1090 if(i < 0) { 1090 if(i < 0) {
1091 if(errno == EINTR) 1091 if(errno == EINTR)
1092 continue; 1092 continue;
1093 mp_msg(MSGT_INPUT,MSGL_ERR,"Select error: %s\n",strerror(errno)); 1093 mp_msg(MSGT_INPUT,MSGL_ERR,MSGTR_INPUT_INPUT_ErrSelect,strerror(errno));
1094 } 1094 }
1095 if(!got_cmd) 1095 if(!got_cmd)
1096 return NULL; 1096 return NULL;
1097 } 1097 }
1098 break; 1098 break;
1114 #endif 1114 #endif
1115 1115
1116 r = mp_input_read_cmd(&cmd_fds[i],&cmd); 1116 r = mp_input_read_cmd(&cmd_fds[i],&cmd);
1117 if(r < 0) { 1117 if(r < 0) {
1118 if(r == MP_INPUT_ERROR) 1118 if(r == MP_INPUT_ERROR)
1119 mp_msg(MSGT_INPUT,MSGL_ERR,"Error on cmd fd %d\n",cmd_fds[i].fd); 1119 mp_msg(MSGT_INPUT,MSGL_ERR,MSGTR_INPUT_INPUT_ErrOnCmdFd,cmd_fds[i].fd);
1120 else if(r == MP_INPUT_DEAD) 1120 else if(r == MP_INPUT_DEAD)
1121 cmd_fds[i].flags |= MP_FD_DEAD; 1121 cmd_fds[i].flags |= MP_FD_DEAD;
1122 continue; 1122 continue;
1123 } 1123 }
1124 ret = mp_input_parse_cmd(cmd); 1124 ret = mp_input_parse_cmd(cmd);
1371 if(bs > 0) bs--; 1371 if(bs > 0) bs--;
1372 r = read(fd,buffer+bs,BS_MAX-1-bs); 1372 r = read(fd,buffer+bs,BS_MAX-1-bs);
1373 if(r < 0) { 1373 if(r < 0) {
1374 if(errno == EINTR) 1374 if(errno == EINTR)
1375 continue; 1375 continue;
1376 mp_msg(MSGT_INPUT,MSGL_ERR,"Error while reading input config file %s: %s\n",file,strerror(errno)); 1376 mp_msg(MSGT_INPUT,MSGL_ERR,MSGTR_INPUT_INPUT_ErrReadingInputConfig,file,strerror(errno));
1377 mp_input_free_binds(binds); 1377 mp_input_free_binds(binds);
1378 close(fd); 1378 close(fd);
1379 return 0; 1379 return 0;
1380 } else if(r == 0) { 1380 } else if(r == 0) {
1381 eof = 1; 1381 eof = 1;
1429 for(end = iter; end[0] != '\0' && strchr(SPACE_CHAR,end[0]) == NULL ; end++) 1429 for(end = iter; end[0] != '\0' && strchr(SPACE_CHAR,end[0]) == NULL ; end++)
1430 /*NOTHING */; 1430 /*NOTHING */;
1431 if(end[0] == '\0') { // Key name doesn't fit in the buffer 1431 if(end[0] == '\0') { // Key name doesn't fit in the buffer
1432 if(buffer == iter) { 1432 if(buffer == iter) {
1433 if(eof && (buffer-iter) == bs) 1433 if(eof && (buffer-iter) == bs)
1434 mp_msg(MSGT_INPUT,MSGL_ERR,"Unfinished binding %s\n",iter); 1434 mp_msg(MSGT_INPUT,MSGL_ERR,MSGTR_INPUT_INPUT_ErrUnfinishedBinding,iter);
1435 else 1435 else
1436 mp_msg(MSGT_INPUT,MSGL_ERR,"Buffer is too small for this key name: %s\n",iter); 1436 mp_msg(MSGT_INPUT,MSGL_ERR,MSGTR_INPUT_INPUT_ErrBuffer2SmallForKeyName,iter);
1437 mp_input_free_binds(binds); 1437 mp_input_free_binds(binds);
1438 return 0; 1438 return 0;
1439 } 1439 }
1440 memmove(buffer,iter,end-iter); 1440 memmove(buffer,iter,end-iter);
1441 bs = end-iter; 1441 bs = end-iter;
1444 { 1444 {
1445 char name[end-iter+1]; 1445 char name[end-iter+1];
1446 strncpy(name,iter,end-iter); 1446 strncpy(name,iter,end-iter);
1447 name[end-iter] = '\0'; 1447 name[end-iter] = '\0';
1448 if(! mp_input_get_input_from_name(name,keys)) { 1448 if(! mp_input_get_input_from_name(name,keys)) {
1449 mp_msg(MSGT_INPUT,MSGL_ERR,"Unknown key '%s'\n",name); 1449 mp_msg(MSGT_INPUT,MSGL_ERR,MSGTR_INPUT_INPUT_ErrUnknownKey,name);
1450 mp_input_free_binds(binds); 1450 mp_input_free_binds(binds);
1451 close(fd); 1451 close(fd);
1452 return 0; 1452 return 0;
1453 } 1453 }
1454 } 1454 }
1459 } else { // Get the command 1459 } else { // Get the command
1460 while(iter[0] == ' ' || iter[0] == '\t') iter++; 1460 while(iter[0] == ' ' || iter[0] == '\t') iter++;
1461 // Found new line 1461 // Found new line
1462 if(iter[0] == '\n' || iter[0] == '\r') { 1462 if(iter[0] == '\n' || iter[0] == '\r') {
1463 int i; 1463 int i;
1464 mp_msg(MSGT_INPUT,MSGL_ERR,"No command found for key %s" ,mp_input_get_key_name(keys[0])); 1464 mp_msg(MSGT_INPUT,MSGL_ERR,MSGTR_INPUT_INPUT_ErrNoCmdForKey,mp_input_get_key_name(keys[0]));
1465 for(i = 1; keys[i] != 0 ; i++) 1465 for(i = 1; keys[i] != 0 ; i++)
1466 mp_msg(MSGT_INPUT,MSGL_ERR,"-%s",mp_input_get_key_name(keys[i])); 1466 mp_msg(MSGT_INPUT,MSGL_ERR,"-%s",mp_input_get_key_name(keys[i]));
1467 mp_msg(MSGT_INPUT,MSGL_ERR,"\n"); 1467 mp_msg(MSGT_INPUT,MSGL_ERR,"\n");
1468 keys[0] = 0; 1468 keys[0] = 0;
1469 if(iter > buffer) { 1469 if(iter > buffer) {
1474 } 1474 }
1475 for(end = iter ; end[0] != '\n' && end[0] != '\r' && end[0] != '\0' ; end++) 1475 for(end = iter ; end[0] != '\n' && end[0] != '\r' && end[0] != '\0' ; end++)
1476 /* NOTHING */; 1476 /* NOTHING */;
1477 if(end[0] == '\0' && ! (eof && ((end+1) - buffer) == bs)) { 1477 if(end[0] == '\0' && ! (eof && ((end+1) - buffer) == bs)) {
1478 if(iter == buffer) { 1478 if(iter == buffer) {
1479 mp_msg(MSGT_INPUT,MSGL_ERR,"Buffer is too small for command %s\n",buffer); 1479 mp_msg(MSGT_INPUT,MSGL_ERR,MSGTR_INPUT_INPUT_ErrBuffer2SmallForCmd,buffer);
1480 mp_input_free_binds(binds); 1480 mp_input_free_binds(binds);
1481 close(fd); 1481 close(fd);
1482 return 0; 1482 return 0;
1483 } 1483 }
1484 memmove(buffer,iter,end - iter); 1484 memmove(buffer,iter,end - iter);
1500 bs -= (end-buffer); 1500 bs -= (end-buffer);
1501 buffer[bs-1] = '\0'; 1501 buffer[bs-1] = '\0';
1502 continue; 1502 continue;
1503 } 1503 }
1504 } 1504 }
1505 mp_msg(MSGT_INPUT,MSGL_ERR,"What are we doing here?\n"); 1505 mp_msg(MSGT_INPUT,MSGL_ERR,MSGTR_INPUT_INPUT_ErrWhyHere);
1506 close(fd); 1506 close(fd);
1507 return 0; 1507 return 0;
1508 } 1508 }
1509 1509
1510 extern char *get_path(char *filename); 1510 extern char *get_path(char *filename);
1538 1538
1539 #ifdef HAVE_JOYSTICK 1539 #ifdef HAVE_JOYSTICK
1540 if(use_joystick) { 1540 if(use_joystick) {
1541 int fd = mp_input_joystick_init(js_dev); 1541 int fd = mp_input_joystick_init(js_dev);
1542 if(fd < 0) 1542 if(fd < 0)
1543 mp_msg(MSGT_INPUT,MSGL_ERR,"Can't init input joystick\n"); 1543 mp_msg(MSGT_INPUT,MSGL_ERR,MSGTR_INPUT_INPUT_ErrCantInitJoystick);
1544 else 1544 else
1545 mp_input_add_key_fd(fd,1,mp_input_joystick_read,(mp_close_func_t)close); 1545 mp_input_add_key_fd(fd,1,mp_input_joystick_read,(mp_close_func_t)close);
1546 } 1546 }
1547 #endif 1547 #endif
1548 1548
1563 #endif 1563 #endif
1564 1564
1565 if(in_file) { 1565 if(in_file) {
1566 struct stat st; 1566 struct stat st;
1567 if(stat(in_file,&st)) 1567 if(stat(in_file,&st))
1568 mp_msg(MSGT_INPUT,MSGL_ERR,"Can't stat %s: %s\n",in_file,strerror(errno)); 1568 mp_msg(MSGT_INPUT,MSGL_ERR,MSGTR_INPUT_INPUT_ErrCantStatFile,in_file,strerror(errno));
1569 else { 1569 else {
1570 in_file_fd = open(in_file,S_ISFIFO(st.st_mode) ? O_RDWR : O_RDONLY); 1570 in_file_fd = open(in_file,S_ISFIFO(st.st_mode) ? O_RDWR : O_RDONLY);
1571 if(in_file_fd >= 0) 1571 if(in_file_fd >= 0)
1572 mp_input_add_cmd_fd(in_file_fd,1,NULL,(mp_close_func_t)close); 1572 mp_input_add_cmd_fd(in_file_fd,1,NULL,(mp_close_func_t)close);
1573 else 1573 else
1574 mp_msg(MSGT_INPUT,MSGL_ERR,"Can't open %s: %s\n",in_file,strerror(errno)); 1574 mp_msg(MSGT_INPUT,MSGL_ERR,MSGTR_INPUT_INPUT_ErrCantOpenFile,in_file,strerror(errno));
1575 } 1575 }
1576 } 1576 }
1577 1577
1578 } 1578 }
1579 1579