HuntnGather – Diff between revs 23 and 24

Subversion Repositories:
Rev:
Show entire fileIgnore whitespace
Rev 23 Rev 24
Line 94... Line 94...
94 #if defined ___AsyncIO___ 94 #if defined ___AsyncIO___
95 if((fp = OpenAsync(dbFile, MODE_READ, ASYNC_BUF)) == NULL) { 95 if((fp = OpenAsync(dbFile, MODE_READ, ASYNC_BUF)) == NULL) {
96 #else 96 #else
97 if((fp = fopen(dbFile, "r")) == NULL) { 97 if((fp = fopen(dbFile, "r")) == NULL) {
98 #endif 98 #endif
99 fprintf(stderr, "Unable to open gather database for reading.\n"); 99 fprintf(stderr, "Unable to open '%s' for reading.\n", dbFile);
100 return; 100 return;
101 } 101 }
Line 102... Line 102...
102   102  
103 database = malloc(sizeof(*database)); 103 database = malloc(sizeof(*database));
Line 109... Line 109...
109 line = 0; 109 line = 0;
110 side = 0; 110 side = 0;
111 i = 0; 111 i = 0;
Line 112... Line 112...
112   112  
113 if(verbose) { 113 if(verbose) {
114 fprintf(stdout, "Sorting temporary database file: '%s'\n", dbFile); 114 fprintf(stdout, "Sorting '%s'\n", dbFile);
-   115 }
115 } 116  
116 #if defined ___AsyncIO___ 117 #if defined ___AsyncIO___
117 while(run && (c = ReadCharAsync(fp)) != -1) { 118 while(run && (c = ReadCharAsync(fp)) != -1) {
118 #else 119 #else
119 while(run && fscanf(fp, "%c", &c) == 1) { 120 while(run && fscanf(fp, "%c", &c) == 1) {
Line 166... Line 167...
166 //path = realloc(path, (i + 1 + 1) * sizeof(char)); 167 //path = realloc(path, (i + 1 + 1) * sizeof(char));
167 path[i] = c; 168 path[i] = c;
168 path[i + 1] = '\0'; 169 path[i + 1] = '\0';
169 break; 170 break;
170 default: 171 default:
171 fprintf(stderr, "Database corrupted: %d\n", side); 172 fprintf(stderr, "File '%s' is corrupted.\n", dbFile);
172 break; 173 break;
173 } 174 }
174 ++i; 175 ++i;
175 break; 176 break;
176 } 177 }
Line 189... Line 190...
189 #if defined ___AsyncIO___ 190 #if defined ___AsyncIO___
190 if((fp = OpenAsync(dbFile, MODE_WRITE, ASYNC_BUF)) == NULL) { 191 if((fp = OpenAsync(dbFile, MODE_WRITE, ASYNC_BUF)) == NULL) {
191 #else 192 #else
192 if((fp = fopen(dbFile, "w")) == NULL) { 193 if((fp = fopen(dbFile, "w")) == NULL) {
193 #endif 194 #endif
194 fprintf(stderr, "Unable to open gather database for writing.\n"); 195 fprintf(stderr, "Unable to open '%s' for writing.\n", dbFile);
195 return; 196 return;
196 } 197 }
Line 197... Line 198...
197   198  
198 for(i = 0; i < line; ++i) { 199 for(i = 0; i < line; ++i) {
Line 222... Line 223...
222   223  
223 /* 224 /*
224 * 225 *
225 * Updates a database file "dbFile". 226 * Updates a database file "dbFile".
226 */ 227 */
227 void UpdateDatabase(char *dbFile, stringStack *dirStack, stats *stats) { 228 void CollectFiles(char *dbFile, stringStack *dirStack, stats *stats) {
228 #if defined ___AsyncIO___ 229 #if defined ___AsyncIO___
229 struct AsyncFile *fp; 230 struct AsyncFile *fp;
230 #else 231 #else
231 FILE *fp; 232 FILE *fp;
Line 240... Line 241...
240 #if defined ___AsyncIO___ 241 #if defined ___AsyncIO___
241 if((fp = OpenAsync(dbFile, MODE_WRITE, ASYNC_BUF)) == NULL) { 242 if((fp = OpenAsync(dbFile, MODE_WRITE, ASYNC_BUF)) == NULL) {
242 #else 243 #else
243 if((fp = fopen(dbFile, "w")) == NULL) { 244 if((fp = fopen(dbFile, "w")) == NULL) {
244 #endif 245 #endif
245 fprintf(stderr, "Unable to open gather database for writing.\n"); 246 fprintf(stderr, "Unable to open '%s' for writing.\n", dbFile);
246 return; 247 return;
247 } 248 }
Line -... Line 249...
-   249  
-   250 if(verbose) {
-   251 fprintf(stdout, "Collecting files...\r");
-   252 }
248   253  
249 while(run && !stringStackIsEmpty(dirStack)) { 254 while(run && !stringStackIsEmpty(dirStack)) {
250 #if defined ___AmigaOS___ 255 #if defined ___AmigaOS___
251 // Check if CTRL+C was pressed and abort the program. 256 // Check if CTRL+C was pressed and abort the program.
252 if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) { 257 if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) {
Line 257... Line 262...
257 if((path = stringStackPop(dirStack)) == NULL) { 262 if((path = stringStackPop(dirStack)) == NULL) {
258 return; 263 return;
259 } 264 }
Line 260... Line 265...
260   265  
-   266 if((dir = opendir(path)) == NULL) {
261 if((dir = opendir(path)) == NULL) { 267 fprintf(stderr, "Unable to open '%s' for reading.\n", path);
262 return; 268 return;
Line 263... Line 269...
263 } 269 }
264   270  
Line 357... Line 363...
357 #if defined ___AsyncIO___ 363 #if defined ___AsyncIO___
358 if((fp = OpenAsync(dbFile, MODE_READ, ASYNC_BUF)) == NULL) { 364 if((fp = OpenAsync(dbFile, MODE_READ, ASYNC_BUF)) == NULL) {
359 #else 365 #else
360 if((fp = fopen(dbFile, "r")) == NULL) { 366 if((fp = fopen(dbFile, "r")) == NULL) {
361 #endif 367 #endif
362 fprintf(stderr, "Unable to open gather database for reading.\n"); 368 fprintf(stderr, "Unable to open '%s' for reading.\n", dbFile);
363 return 0; 369 return 0;
364 } 370 }
Line 365... Line 371...
365   371  
366 #if defined ___AsyncIO___ 372 #if defined ___AsyncIO___
Line 382... Line 388...
382   388  
383 /* 389 /*
384 * 390 *
385 * Counts the lines of a file. 391 * Counts the lines of a file.
386 */ 392 */
387 int GetFileLines(char *dbFile) { 393 int CountFileLines(char *dbFile) {
388 #if defined ___AsyncIO___ 394 #if defined ___AsyncIO___
389 struct AsyncFile *fp; 395 struct AsyncFile *fp;
390 LONG c; 396 LONG c;
391 #else 397 #else
Line 397... Line 403...
397 #if defined ___AsyncIO___ 403 #if defined ___AsyncIO___
398 if((fp = OpenAsync(dbFile, MODE_READ, ASYNC_BUF)) == NULL) { 404 if((fp = OpenAsync(dbFile, MODE_READ, ASYNC_BUF)) == NULL) {
399 #else 405 #else
400 if((fp = fopen(dbFile, "r")) == NULL) { 406 if((fp = fopen(dbFile, "r")) == NULL) {
401 #endif 407 #endif
402 fprintf(stderr, "Unable to open gather database for reading.\n"); 408 fprintf(stderr, "Unable to open '%s' for reading.\n", dbFile);
403 return 0; 409 return 0;
404 } 410 }
Line 405... Line 411...
405   411  
406 lines = 0; 412 lines = 0;
Line 441... Line 447...
441 int count; 447 int count;
Line 442... Line 448...
442   448  
Line 443... Line 449...
443 tmpNames = malloc(files * sizeof(*tmpNames)); 449 tmpNames = malloc(files * sizeof(*tmpNames));
444   450  
445 if(verbose) { 451 if(verbose) {
Line 446... Line 452...
446 fprintf(stdout, "Creating temporary files.\r"); 452 fprintf(stdout, "Creating temporary files...\r");
447 } 453 }
448   454  
Line 455... Line 461...
455 continue; 461 continue;
456 } 462 }
457 #endif 463 #endif
458 tmpNames[count] = tmpnam(NULL); 464 tmpNames[count] = tmpnam(NULL);
Line -... Line 465...
-   465  
-   466 // Remove file to ensure that the file is empty.
-   467 remove(tmpNames[count]);
459   468  
460 if(verbose) { 469 if(verbose) {
461 fprintf(stdout, "Creating temporary files: %d%%\r", 100 - (int)(((float)count / files) * 100.0)); 470 fprintf(stdout, "Creating temporary files: %d%%\r", 100 - (int)(((float)count / files) * 100.0));
462 } 471 }
Line 487... Line 496...
487 #if defined ___AsyncIO___ 496 #if defined ___AsyncIO___
488 if((fp = OpenAsync(dbFile, MODE_READ, ASYNC_BUF)) == NULL) { 497 if((fp = OpenAsync(dbFile, MODE_READ, ASYNC_BUF)) == NULL) {
489 #else 498 #else
490 if((fp = fopen(dbFile, "r")) == NULL) { 499 if((fp = fopen(dbFile, "r")) == NULL) {
491 #endif 500 #endif
492 fprintf(stderr, "Unable to open gather database '%s' for reading.\n", dbFile); 501 fprintf(stderr, "Unable to open '%s' for reading.\n", dbFile);
493 return; 502 return;
494 } 503 }
Line 495... Line 504...
495   504  
496 #if defined ___AsyncIO___ 505 #if defined ___AsyncIO___
497 if((tp = OpenAsync(tmpNames[--tmpFiles], MODE_WRITE, ASYNC_BUF)) == NULL) { 506 if((tp = OpenAsync(tmpNames[--tmpFiles], MODE_WRITE, ASYNC_BUF)) == NULL) {
498 #else 507 #else
499 if((tp = fopen(tmpNames[--tmpFiles], "w")) == NULL) { 508 if((tp = fopen(tmpNames[--tmpFiles], "w")) == NULL) {
500 #endif 509 #endif
-   510 fprintf(stderr, "Unable to open '%s' for writing.\n", tmpNames[tmpFiles]);
-   511 #if defined ___AsyncIO___
-   512 CloseAsync(fp);
-   513 #else
-   514 fclose(fp);
501 fprintf(stderr, "Unable to open temporary file '%s' for writing.\n", tmpNames[tmpFiles]); 515 #endif
502 return; 516 return;
Line 503... Line 517...
503 } 517 }
504   518  
505 if(verbose) { 519 if(verbose) {
Line 506... Line 520...
506 fprintf(stdout, "Writing to temporary files.\r"); 520 fprintf(stdout, "Writing to temporary files...\r");
507 } 521 }
508   522  
Line 533... Line 547...
533 #if defined ___AsyncIO___ 547 #if defined ___AsyncIO___
534 if(WriteCharAsync(tp, (UBYTE)c) != 1) { 548 if(WriteCharAsync(tp, (UBYTE)c) != 1) {
535 #else 549 #else
536 if(fprintf(tp, "%c", c) != 1) { 550 if(fprintf(tp, "%c", c) != 1) {
537 #endif 551 #endif
538 fprintf(stderr, "Unable to write to temporary file '%s'.\n", tmpNames[tmpFiles]); 552 fprintf(stderr, "Unable to write to '%s'.\n", tmpNames[tmpFiles]);
539 #if defined ___AsyncIO___ 553 #if defined ___AsyncIO___
540 CloseAsync(tp); 554 CloseAsync(tp);
541 CloseAsync(fp); 555 CloseAsync(fp);
542 #else 556 #else
543 fclose(tp); 557 fclose(tp);
Line 558... Line 572...
558 if((tp = OpenAsync(tmpNames[--tmpFiles], MODE_WRITE, ASYNC_BUF)) == NULL) { 572 if((tp = OpenAsync(tmpNames[--tmpFiles], MODE_WRITE, ASYNC_BUF)) == NULL) {
559 #else 573 #else
560 fclose(tp); 574 fclose(tp);
561 if((tp = fopen(tmpNames[--tmpFiles], "w")) == NULL) { 575 if((tp = fopen(tmpNames[--tmpFiles], "w")) == NULL) {
562 #endif 576 #endif
563 fprintf(stderr, "Unable to open temporary file '%s' for writing.\n", tmpNames[tmpFiles]); 577 fprintf(stderr, "Unable to open '%s' for writing.\n", tmpNames[tmpFiles]);
564 #if defined ___AsyncIO___ 578 #if defined ___AsyncIO___
565 CloseAsync(tp); -  
566 CloseAsync(fp); 579 CloseAsync(fp);
567 #else 580 #else
568 fclose(tp); -  
569 fclose(fp); 581 fclose(fp);
570 #endif 582 #endif
-   583 return;
571 } 584 }
572 lines = 0; 585 lines = 0;
573 break; 586 break;
574 } 587 }
575 break; 588 break;
Line 577... Line 590...
577 #if defined ___AsyncIO___ 590 #if defined ___AsyncIO___
578 if(WriteCharAsync(tp, (UBYTE)c) != 1) { 591 if(WriteCharAsync(tp, (UBYTE)c) != 1) {
579 #else 592 #else
580 if(fprintf(tp, "%c", c) != 1) { 593 if(fprintf(tp, "%c", c) != 1) {
581 #endif 594 #endif
582 fprintf(stderr, "Unable to write to temporary file '%s'.\n", tmpNames[tmpFiles]); 595 fprintf(stderr, "Unable to write to '%s'.\n", tmpNames[tmpFiles]);
583 #if defined ___AsyncIO___ 596 #if defined ___AsyncIO___
584 CloseAsync(tp); 597 CloseAsync(tp);
585 CloseAsync(fp); 598 CloseAsync(fp);
586 #else 599 #else
587 fclose(tp); 600 fclose(tp);
Line 591... Line 604...
591 } 604 }
592 break; 605 break;
593 } 606 }
594 } 607 }
Line -... Line 608...
-   608  
595   609 if(verbose) {
-   610 fprintf(stdout, "\n");
Line 596... Line 611...
596 fprintf(stdout, "\n"); 611 }
597   612  
598 #if defined ___AsyncIO___ 613 #if defined ___AsyncIO___
599 CloseAsync(tp); 614 CloseAsync(tp);
Line 604... Line 619...
604 #endif 619 #endif
605 } 620 }
Line 606... Line 621...
606   621  
607 /* 622 /*
608 * 623 *
609 * Skips a line in a database file "fp". 624 * Skips a line in a file.
Line 610... Line 625...
610 */ 625 */
611   626  
612 #if defined ___AsyncIO___ 627 #if defined ___AsyncIO___
Line 632... Line 647...
632 } 647 }
633 } 648 }
Line 634... Line 649...
634   649  
635 /* 650 /*
636 * 651 *
637 * Reads a line from the database file "fp". 652 * Reads a line from a file.
638 */ 653 */
639 #if defined ___AsyncIO___ 654 #if defined ___AsyncIO___
640 char *ReadLine(struct AsyncFile *fp) { 655 char *ReadLine(struct AsyncFile *fp) {
641 LONG c; 656 LONG c;
Line 693... Line 708...
693   708  
694 /* 709 /*
695 * 710 *
696 * Merges temporary files "tmpNames" into a database "dbFile". 711 * Merges temporary files "tmpNames" into a database "dbFile".
697 */ 712 */
698 void MergeDatabase(char *dbFile, char **tmpNames, int files, int lines) { 713 void MergeTemporaryFiles(char *dbFile, char **tmpNames, int files, int lines) {
699 #if defined ___AsyncIO___ 714 #if defined ___AsyncIO___
700 struct AsyncFile *fp; 715 struct AsyncFile *fp;
701 struct AsyncFile **tp; 716 struct AsyncFile **tp;
702 #else 717 #else
Line 712... Line 727...
712 #if defined ___AsyncIO___ 727 #if defined ___AsyncIO___
713 if((fp = OpenAsync(dbFile, MODE_WRITE, ASYNC_BUF)) == NULL) { 728 if((fp = OpenAsync(dbFile, MODE_WRITE, ASYNC_BUF)) == NULL) {
714 #else 729 #else
715 if((fp = fopen(dbFile, "w")) == NULL) { 730 if((fp = fopen(dbFile, "w")) == NULL) {
716 #endif 731 #endif
717 fprintf(stderr, "Unable to open gather database for writing.\n"); 732 fprintf(stderr, "Unable to open '%s' for writing.\n", dbFile);
718 return; 733 return;
719 } 734 }
Line 720... Line 735...
720   735  
721 // Allocate as many file pointers as temporary files. 736 // Allocate as many file pointers as temporary files.
Line 726... Line 741...
726 #if defined ___AsyncIO___ 741 #if defined ___AsyncIO___
727 if((tp[i] = OpenAsync(tmpNames[i], MODE_READ, ASYNC_BUF)) == NULL) { 742 if((tp[i] = OpenAsync(tmpNames[i], MODE_READ, ASYNC_BUF)) == NULL) {
728 #else 743 #else
729 if((tp[i] = fopen(tmpNames[i], "r")) == NULL) { 744 if((tp[i] = fopen(tmpNames[i], "r")) == NULL) {
730 #endif 745 #endif
731 fprintf(stderr, "Unable to open temporary file '%s' for reading.\n", tmpNames[i]); 746 fprintf(stderr, "Unable to open '%s' for reading.\n", tmpNames[i]);
732 // Close all temporary files. 747 // Close all temporary files.
733 --i; -  
734 while(i >= 0) { 748 while(--i > -1) {
735 #if defined ___AsyncIO___ 749 #if defined ___AsyncIO___
736 CloseAsync(tp[i]); 750 CloseAsync(tp[i]);
737 #else 751 #else
738 fclose(tp[i]); 752 fclose(tp[i]);
739 #endif 753 #endif
740 } 754 }
-   755 #if defined ___AsyncIO___
-   756 CloseAsync(fp);
-   757 #else
-   758 fclose(fp);
-   759 #endif
741 return; 760 return;
742 } 761 }
743 } 762 }
Line 744... Line 763...
744   763  
745 if(verbose) { 764 if(verbose) {
746 fprintf(stdout, "Merging all database lines in temporary files.\r"); 765 fprintf(stdout, "Merging all files...\r");
Line 747... Line 766...
747 } 766 }
748   767  
749 count = lines; 768 count = lines;
Line 756... Line 775...
756 continue; 775 continue;
757 } 776 }
758 #endif 777 #endif
759 // Find the smallest line in all temporary files. 778 // Find the smallest line in all temporary files.
760 if(verbose) { 779 if(verbose) {
761 fprintf(stdout, "Merging all database lines in temporary files: %d%%.\r", 100 - (int)(((float)count / lines) * 100.0)); 780 fprintf(stdout, "Merging all files: %d%%.\r", 100 - (int)(((float)count / lines) * 100.0));
762 } 781 }
Line 763... Line 782...
763   782  
764 min = NULL; 783 min = NULL;
765 for(i = 0; i < files; ++i) { 784 for(i = 0; i < files; ++i) {
Line 796... Line 815...
796 free(min); 815 free(min);
797 } 816 }
798 } 817 }
Line 799... Line 818...
799   818  
800 // Write out any remaining contents from the temporary files. 819 // Write out any remaining contents from the temporary files.
-   820 for(i = 0; run && i < files; ++i) {
-   821 #if defined ___AmigaOS___
-   822 // Check if CTRL+C was pressed and abort the program.
-   823 if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) {
-   824 run = FALSE;
-   825 continue;
-   826 }
801 for(i = 0; i < files; ++i) { 827 #endif
802 tmp = ReadLine(tp[i]); 828 tmp = ReadLine(tp[i]);
803 if(tmp == NULL) { 829 if(tmp == NULL) {
804 continue; 830 continue;
805 } 831 }
Line 810... Line 836...
810 fprintf(fp, "%s\n", tmp); 836 fprintf(fp, "%s\n", tmp);
811 #endif 837 #endif
812 free(tmp); 838 free(tmp);
813 } 839 }
Line 814... Line 840...
814   840  
815 // Close and delete all temporary files. 841 // Close all temporary files.
816 for(i = 0; i < files; ++i) { 842 for(i = 0; i < files; ++i) {
817 #if defined ___AsyncIO___ 843 #if defined ___AsyncIO___
818 CloseAsync(tp[i]); 844 CloseAsync(tp[i]);
819 #else 845 #else
820 fclose(tp[i]); 846 fclose(tp[i]);
821 #endif -  
822 // Delete temporary file. -  
823 remove(tmpNames[i]); 847 #endif
Line 824... Line 848...
824 } 848 }
825   849  
826 if(verbose) { 850 if(verbose) {
Line 834... Line 858...
834 #endif 858 #endif
835 } 859 }
Line 836... Line 860...
836   860  
837 /* 861 /*
-   862 *
-   863 * Deletes temporary files.
-   864 */
-   865 void DeleteTemporaryFiles(char **tmpNames, int tmpFiles) {
-   866 int i = tmpFiles;
-   867  
-   868 if(verbose) {
-   869 fprintf(stdout, "Deleting temporary files...\r");
-   870 }
-   871  
-   872 do {
-   873 remove(tmpNames[i]);
-   874 } while(--i > -1);
-   875  
-   876 if(verbose) {
-   877 fprintf(stdout, "\n");
-   878 }
-   879 }
-   880  
-   881 /*
838 * 882 *
839 * Indexes a "path" by creating a database "dbFile". 883 * Indexes a "path" by creating a database "dbFile".
840 */ 884 */
841 void Gather(char *dbFile, char *path) { 885 void Gather(char *dbFile, char *path) {
842 stringStack *stack = stringStackCreate(1); 886 stringStack *stack = stringStackCreate(1);
Line 851... Line 895...
851   895  
852 // Push the first path onto the stack. 896 // Push the first path onto the stack.
Line 853... Line 897...
853 stringStackPush(stack, path); 897 stringStackPush(stack, path);
854   898  
Line 855... Line 899...
855 // Generate the database file. 899 // Generate the database file.
856 UpdateDatabase(dbFile, stack, stats); 900 CollectFiles(dbFile, stack, stats);
857   901  
Line 858... Line 902...
858 // Get the database metrics. 902 // Get the database metrics.
859 dbSize = GetFileSize(dbFile); 903 dbSize = GetFileSize(dbFile);
Line 860... Line 904...
860 dbLines = GetFileLines(dbFile); 904 dbLines = CountFileLines(dbFile);
Line 875... Line 919...
875 if((tmpNames = CreateTemporaryFiles(tmpFiles)) == NULL) { 919 if((tmpNames = CreateTemporaryFiles(tmpFiles)) == NULL) {
876 fprintf(stderr, "Unable to create temporary files.\n"); 920 fprintf(stderr, "Unable to create temporary files.\n");
877 return; 921 return;
878 } 922 }
Line 879... Line 923...
879   923  
880 // Write "tmpLines" to temporary files in "tmpFiles" from "dbFile". 924 // Write "tmpLines" to temporary files in "tmpNames" from "dbFile".
Line 881... Line 925...
881 WriteTemporaryFiles(dbFile, tmpNames, tmpFiles, tmpLines, dbLines); 925 WriteTemporaryFiles(dbFile, tmpNames, tmpFiles, tmpLines, dbLines);
882   926  
883 // Sort the temporary files. 927 // Sort the temporary files.
884 for(i = 0; i < tmpFiles; ++i) { 928 for(i = 0; run && i < tmpFiles; ++i) {
Line -... Line 929...
-   929 SortDatabase(tmpNames[i]);
885 SortDatabase(tmpNames[i]); 930 }
-   931  
-   932 // Merge all the temporary files to the database file.
-   933 MergeTemporaryFiles(dbFile, tmpNames, tmpFiles, dbLines);
886 } 934  
Line 887... Line 935...
887   935 // Remove all temporary files.
888 MergeDatabase(dbFile, tmpNames, tmpFiles, dbLines); 936 DeleteTemporaryFiles(tmpNames, tmpFiles);
889 } 937 }
Line 956... Line 1004...
956 fprintf(stderr, "Path '%s' is not a directory.\n", argv[optind]); 1004 fprintf(stderr, "Path '%s' is not a directory.\n", argv[optind]);
957 return 1; 1005 return 1;
958 } 1006 }
Line 959... Line 1007...
959   1007  
960 if(verbose) { 1008 if(verbose) {
961 fprintf(stdout, "Gathering to database file: %s\n", dbFile); 1009 fprintf(stdout, "Gathering to %s\n", dbFile);
Line 962... Line 1010...
962 } 1010 }
963   1011