1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 4270 4271 4272 4273 4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 4336 4337 4338 4339 4340 4341 4342 4343 4344 4345 4346 4347 4348 4349 4350 4351 4352 4353 4354 4355 4356 4357 4358 4359 4360 4361 4362 4363 4364 4365 4366 4367 4368 4369 4370 4371 4372 4373 4374 4375 4376 4377 4378 4379 4380 4381 4382 4383 4384 4385 4386 4387 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 4590 4591 4592 4593 4594 4595 4596 4597 4598 4599 4600 4601 4602 4603 4604 4605 4606 4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624 4625 4626 4627 4628 4629 4630 4631 4632 4633 4634 4635 4636 4637 4638 4639 4640 4641 4642 4643 4644 4645 4646 4647 4648 4649 4650 4651 4652 4653 4654 4655 4656 4657 4658 4659 4660 4661 4662 4663 4664 4665 4666 4667 4668 4669 4670 4671 4672 4673 4674 4675 4676 4677 4678 4679 4680 4681 4682 4683 4684 4685 4686 4687 4688 4689 4690 4691 4692 4693 4694 4695 4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709 4710 4711 4712 4713 4714 4715 4716 4717 4718 4719 4720 4721 4722 4723 4724 4725 4726 4727 4728 4729 4730 4731 4732 4733 4734 4735 4736 4737 4738 4739 4740 4741 4742 4743 4744 4745 4746 4747
|
% generated by GAPDoc2LaTeX from XML source (Frank Luebeck)
\documentclass[a4paper,11pt]{report}
\usepackage[top=37mm,bottom=37mm,left=27mm,right=27mm]{geometry}
\sloppy
\pagestyle{myheadings}
\usepackage{amssymb}
\usepackage[latin1]{inputenc}
\usepackage{makeidx}
\makeindex
\usepackage{color}
\definecolor{FireBrick}{rgb}{0.5812,0.0074,0.0083}
\definecolor{RoyalBlue}{rgb}{0.0236,0.0894,0.6179}
\definecolor{RoyalGreen}{rgb}{0.0236,0.6179,0.0894}
\definecolor{RoyalRed}{rgb}{0.6179,0.0236,0.0894}
\definecolor{LightBlue}{rgb}{0.8544,0.9511,1.0000}
\definecolor{Black}{rgb}{0.0,0.0,0.0}
\definecolor{linkColor}{rgb}{0.0,0.0,0.554}
\definecolor{citeColor}{rgb}{0.0,0.0,0.554}
\definecolor{fileColor}{rgb}{0.0,0.0,0.554}
\definecolor{urlColor}{rgb}{0.0,0.0,0.554}
\definecolor{promptColor}{rgb}{0.0,0.0,0.589}
\definecolor{brkpromptColor}{rgb}{0.589,0.0,0.0}
\definecolor{gapinputColor}{rgb}{0.589,0.0,0.0}
\definecolor{gapoutputColor}{rgb}{0.0,0.0,0.0}
%% for a long time these were red and blue by default,
%% now black, but keep variables to overwrite
\definecolor{FuncColor}{rgb}{0.0,0.0,0.0}
%% strange name because of pdflatex bug:
\definecolor{Chapter }{rgb}{0.0,0.0,0.0}
\definecolor{DarkOlive}{rgb}{0.1047,0.2412,0.0064}
\usepackage{fancyvrb}
\usepackage{mathptmx,helvet}
\usepackage[T1]{fontenc}
\usepackage{textcomp}
\usepackage[
pdftex=true,
bookmarks=true,
a4paper=true,
pdftitle={Written with GAPDoc},
pdfcreator={LaTeX with hyperref package / GAPDoc},
colorlinks=true,
backref=page,
breaklinks=true,
linkcolor=linkColor,
citecolor=citeColor,
filecolor=fileColor,
urlcolor=urlColor,
pdfpagemode={UseNone},
]{hyperref}
\newcommand{\maintitlesize}{\fontsize{50}{55}\selectfont}
% write page numbers to a .pnr log file for online help
\newwrite\pagenrlog
\immediate\openout\pagenrlog =\jobname.pnr
\immediate\write\pagenrlog{PAGENRS := [}
\newcommand{\logpage}[1]{\protect\write\pagenrlog{#1, \thepage,}}
%% were never documented, give conflicts with some additional packages
\newcommand{\GAP}{\textsf{GAP}}
%% nicer description environments, allows long labels
\usepackage{enumitem}
\setdescription{style=nextline}
%% depth of toc
\setcounter{tocdepth}{1}
%% command for ColorPrompt style examples
\newcommand{\gapprompt}[1]{\color{promptColor}{\bfseries #1}}
\newcommand{\gapbrkprompt}[1]{\color{brkpromptColor}{\bfseries #1}}
\newcommand{\gapinput}[1]{\color{gapinputColor}{#1}}
\begin{document}
\logpage{[ 0, 0, 0 ]}
\begin{titlepage}
\mbox{}\vfill
\begin{center}{\maintitlesize \textbf{\textsf{Browse}\mbox{}}}\\
\vfill
\hypersetup{pdftitle=\textsf{Browse}}
\markright{\scriptsize \mbox{}\hfill \textsf{Browse} \hfill\mbox{}}
{\Huge ( Version 1.8.21 ) \mbox{}}\\[1cm]
{March 2023\mbox{}}\\[1cm]
\mbox{}\\[2cm]
{\Large \textbf{ Thomas Breuer \mbox{}}}\\
{\Large \textbf{ Frank L{\"u}beck \mbox{}}}\\
\hypersetup{pdfauthor= Thomas Breuer ; Frank L{\"u}beck }
\end{center}\vfill
\mbox{}\\
{\mbox{}\\
\small \noindent \textbf{ Thomas Breuer } Email: \href{mailto://Thomas.Breuer@Math.RWTH-Aachen.De} {\texttt{Thomas.Breuer@Math.RWTH-Aachen.De}}\\
Homepage: \href{https://www.math.rwth-aachen.de/~Thomas.Breuer} {\texttt{https://www.math.rwth-aachen.de/\texttt{\symbol{126}}Thomas.Breuer}}}\\
{\mbox{}\\
\small \noindent \textbf{ Frank L{\"u}beck } Email: \href{mailto://Frank.Luebeck@Math.RWTH-Aachen.De} {\texttt{Frank.Luebeck@Math.RWTH-Aachen.De}}\\
Homepage: \href{https://www.math.rwth-aachen.de/~Frank.Luebeck} {\texttt{https://www.math.rwth-aachen.de/\texttt{\symbol{126}}Frank.Luebeck}}}\\
\end{titlepage}
\newpage\setcounter{page}{2}
{\small
\section*{Copyright}
\logpage{[ 0, 0, 1 ]}
{\copyright} 2006-2023 by Thomas Breuer and Frank L{\"u}beck
This package may be distributed under the terms and conditions of the GNU
Public License Version 3 or later, see \href{http://www.gnu.org/licenses} {\texttt{http://www.gnu.org/licenses}}. \mbox{}}\\[1cm]
\newpage
\def\contentsname{Contents\logpage{[ 0, 0, 2 ]}}
\tableofcontents
\newpage
\chapter{\textcolor{Chapter }{Introduction and Overview}}\label{ch:intro}
\logpage{[ 1, 0, 0 ]}
\hyperdef{L}{X794AAAFB7FFAA46C}{}
{
\section{\textcolor{Chapter }{Introduction}}\label{sec:intro}
\logpage{[ 1, 1, 0 ]}
\hyperdef{L}{X7DFB63A97E67C0A1}{}
{
The motivation of the package \textsf{Browse} was to provide better functionality for displaying two-dimensional arrays of
data (e.g., character tables): moving through the data without loosing row and
column labels, searching for text, displaying extra information, hiding
information, allowing interactive user input, ...
We wanted to achieve this by using the capabilities of the terminal emulations
in which \textsf{GAP} is running, and not by some external graphical user interface. For this we
have chosen to use the widely available \texttt{C}-library \texttt{ncurses}, see \cite{NCursesWeb}. It contains functions to find out terminal capabilities, to change
properties of terminals, to place text, to handle several windows with
overlapping, ... To use these functions the terminal is switched to a \emph{visual mode} \index{visual mode} so that the display of the non-visual mode of your terminal in which \textsf{GAP} is running is not clobbered.
\textsf{Browse} has now three levels of functionality:
\begin{description}
\item[{A low level interface to \texttt{ncurses}}] This may be interesting for all kinds of applications which want to display
text with some markup including \index{colors as text attributes}colors, maybe in several windows, using the available capabilities of a
terminal.
\item[{A medium level interface to a generic function \texttt{NCurses.BrowseGeneric} (\ref{NCurses.BrowseGeneric})}] This is for displaying two-dimensional arrays of data, handles labels for rows
and columns, searching, sorting, binding keys to actions, ... If you want to
implement such applications for further kinds of data, first look at the
examples in Section \texttt{BrowseData.IsBrowseTable} (\ref{BrowseData.IsBrowseTable}), then check what can be copied from the examples in Chapter \ref{ch:appl}, and consult the descriptions in Chapters \ref{chap:browse-user} and \ref{chap:browse-prg}.
\item[{Applications of these interfaces}] We provide some applications of the \texttt{ncurses} interface and of the generic \texttt{NCurses.BrowseGeneric} (\ref{NCurses.BrowseGeneric}) function. These may be interesting for end users, and also as examples for
programmers of further applications. This includes (of course) a method for
browsing through character tables, functions for browsing through data
collections, several games,\index{game} and an interface for demos.
\end{description}
Users interested only in these applications should perhaps just try \texttt{NCurses.Demo()}. }
\section{\textcolor{Chapter }{Overview}}\label{sec:overview}
\logpage{[ 1, 2, 0 ]}
\hyperdef{L}{X8389AD927B74BA4A}{}
{
\subsection{\textcolor{Chapter }{The \texttt{ncurses} interface}}\label{ssec:ov_ncurses}
\logpage{[ 1, 2, 1 ]}
\hyperdef{L}{X87A6D24784C21E54}{}
{
Chapter \ref{ch:curses} describes \textsf{GAP}'s interface to the \texttt{ncurses} \texttt{C}-library. The imported \texttt{C}-functions are shortly explained, but for further details we refer to the
documentation of that library. There are also a few utility functions on \textsf{GAP} level, such as \texttt{NCurses.SetTerm} (\ref{NCurses.SetTerm}), which simplify the use of the library.
The concept of an \emph{attribute line}\index{attribute line}, see \texttt{NCurses.IsAttributeLine} (\ref{NCurses.IsAttributeLine}), helps to deal with text with markup for its display in a terminal window.
This chapter is for users who want to write their own applications of \texttt{ncurses}. }
\subsection{\textcolor{Chapter }{Applications of \texttt{ncurses}}}\label{ssec:ov_ncappl}
\logpage{[ 1, 2, 2 ]}
\hyperdef{L}{X80C054D881502061}{}
{
In Chapter \ref{ch:util} we describe some interactive applications of the \texttt{ncurses} interface. For example, there is \texttt{NCurses.Select} (\ref{NCurses.Select}) for asking a user to choose one or several of a given list of items. There is
also a demo function \texttt{NCurses.Demo} (\ref{NCurses.Demo}) which we use to demonstrate features of the \textsf{Browse} package, but it may be interesting for other kinds of demos as well. }
\subsection{\textcolor{Chapter }{The interface to browse two-dimensional arrays}}\label{ssec:ov_genbrowse}
\logpage{[ 1, 2, 3 ]}
\hyperdef{L}{X7CF47ACC83A95689}{}
{
Chapters \ref{chap:browse-user} and \ref{chap:browse-prg} describe the interface to a generic function \texttt{NCurses.BrowseGeneric} (\ref{NCurses.BrowseGeneric}) which can be used for an interactive display of two-dimensional arrays of
data. The first of these covers the basic functionality which may be
sufficient for many applications and the second gives more technical details.
With interactive display we mean that it is not only possible to scroll
through the data, but one can search for strings, sort by rows or columns,
select entries, bind arbitrary actions to keys and mouse events, ask for help,
and more. }
\subsection{\textcolor{Chapter }{Applications of the generic function \texttt{NCurses.BrowseGeneric}}}\label{ssec:ov_browseappl}
\logpage{[ 1, 2, 4 ]}
\hyperdef{L}{X7A0055DE7A2C5DC9}{}
{
In Chapter \ref{ch:appl} we describe several applications which are using the generic \texttt{NCurses.BrowseGeneric} (\ref{NCurses.BrowseGeneric}) interface introduced before. They are provided as prototype applications and
so we include some implementation remarks in their documentation.
Users who just want to use these applications hopefully do not need to read
this \textsf{Browse} manual, all applications are coming with built-in help windows.
There are different kinds of applications. First, there are methods for
browsing through character tables and tables of marks (our original motivation
for this package). Then there are applications for browsing through data
collections, e.g., the data available through the \textsf{AtlasRep} package, the \textsf{GAP} bibliography or the sections of the \textsf{GAP} manuals. Finally, there are several games like Sam Loyd's fifteen puzzle
(generalized), peg solitaire, and Sudoku (including functions to create new
puzzles and to solve puzzles). }
}
\section{\textcolor{Chapter }{User preferences provided by the \textsf{Browse} package}}\label{sec:pkg_userprefs}
\logpage{[ 1, 3, 0 ]}
\hyperdef{L}{X825F23FF825334B4}{}
{
See \texttt{SetUserPreference} (\textbf{Reference: SetUserPreference}) for \textsf{GAP}'s user preferences mechanism, and \texttt{BrowseUserPreferences} (\ref{BrowseUserPreferences}) for viewing and modifying user preferences.
\subsection{\textcolor{Chapter }{The user preference \texttt{EnableMouseEvents}}}\label{subsec:EnableMouseEvents}
\logpage{[ 1, 3, 1 ]}
\hyperdef{L}{X859EAEDA850D3B02}{}
{
This user preference defines whether mouse events are enabled by default in
visual mode (value \texttt{true}) or not (value \texttt{false}, this is the default). During the \textsf{GAP} session, the value can be changed using \texttt{NCurses.UseMouse} (\ref{NCurses.UseMouse}). Inside browse applications based on \texttt{NCurses.BrowseGeneric} (\ref{NCurses.BrowseGeneric}) or \texttt{NCurses.Select} (\ref{NCurses.Select}), the value can be toggled usually by hitting the \textsc{M} key. }
\subsection{\textcolor{Chapter }{The user preference \texttt{SelectHelpMatches}}}\label{subsec:SelectHelpMatches}
\logpage{[ 1, 3, 2 ]}
\hyperdef{L}{X7D242D4286EAB00A}{}
{
In the case that the \textsf{GAP} help system finds multiple matches, \texttt{true} (the default) means that the user can choose one entry from a list that is
shown via \texttt{NCurses.Select} (\ref{NCurses.Select}), and \texttt{false} means that the matches are just shown in a pager. }
\subsection{\textcolor{Chapter }{The user preference \texttt{SelectPackageName}}}\label{subsec:SelectPackageName}
\logpage{[ 1, 3, 3 ]}
\hyperdef{L}{X7BC3B5827A4B09C3}{}
{
In the case that \texttt{LoadPackage} (\textbf{Reference: LoadPackage}) is called with a prefix of some package names, \texttt{true} (the default) means that the user can choose one matching entry, and \texttt{false} means that the matches are just printed. }
}
}
\chapter{\textcolor{Chapter }{Interface to the \texttt{ncurses} Library}}\label{ch:curses}
\logpage{[ 2, 0, 0 ]}
\hyperdef{L}{X7E049B1185A56B30}{}
{
In this chapter we describe the \textsf{GAP} interface to the \textsf{GNU} \texttt{curses}/\texttt{ncurses} \texttt{C}-library. This library contains routines to manipulate the contents of
terminal windows. It allows one to write programs which should work on a wide
variety of terminal emulations with different sets of capabilities.
This technical chapter is intended for readers who want to program new
applications using the \texttt{ncurses} functionality. If you are only interested in the function \texttt{NCurses.BrowseGeneric} (\ref{NCurses.BrowseGeneric}) from this package or some of its applications you can skip this chapter.
Detailed documentation of the \texttt{ncurses} library is probably available in your operating system (try \texttt{man ncurses}) and from the web (see for example \cite{NCursesWeb}). Here, we only give short reminders about the functions provided in the \textsf{GAP} interface and explain how to use the \textsf{GAP} functions.
\section{\textcolor{Chapter }{The \texttt{ncurses} Library}}\label{sec:cursesC}
\logpage{[ 2, 1, 0 ]}
\hyperdef{L}{X85DE9B75837BA65B}{}
{
In this section we list the functions from the GNU \texttt{ncurses} library and its \texttt{panel} extension which are made available in \textsf{GAP} via the \textsf{Browse} package. See the following section \ref{sec:cursesGAP} for explanations how to use these functions from within \textsf{GAP}.
The basic objects to manipulate are called \emph{windows}, they correspond to rectangular regions of the terminal screen. Windows can
overlap but \texttt{ncurses} cannot handle this for the display. Therefore windows can be wrapped in \emph{panels}, they provide a display depth for windows and it is possible to move panels
to the top and bottom of the display or to hide a panel.
We will not import all the functions of the \texttt{ncurses} library to \textsf{GAP}. For example, there are many pairs of functions with the same name except for
a leading \texttt{w} (like \texttt{move} and \texttt{wmove} for moving the cursor in a window). Here, we only import the versions with \texttt{w}, which get a window as first argument. The functions without \texttt{w} are for the \texttt{ncurses} standard screen window \texttt{stdscr} which is available as window \texttt{0} in \textsf{GAP}. Similarly, there are functions with the same name except for an extra \texttt{n} (like \texttt{waddstr} and \texttt{waddnstr} for placing a string into a window). Here, we only import the safer functions
with \texttt{n} which get the number of characters to write as argument. (More convenient
functions are then implemented on the \textsf{GAP} level.)
\subsection{\textcolor{Chapter }{Setting the terminal}}\label{ssec:ncursesTermset}
\logpage{[ 2, 1, 1 ]}
\hyperdef{L}{X8499A3A384BF1F2D}{}
{
We first list flags for setting the basic behavior of a terminal. With \texttt{savetty}/\texttt{resetty} a setting can be stored and recovered.
\begin{description}
\item[{\index{savetty@\texttt{savetty}}\texttt{savetty()}}] This stores the current setting of the terminal in a buffer.
\item[{\index{resetty@\texttt{resetty}}\texttt{resetty()}}] This resets the terminal to what was stored in the last call to \texttt{savetty}.
\item[{\index{cbreak@\texttt{cbreak}} \index{nocbreak@\texttt{nocbreak}}\texttt{cbreak()/nocbreak()}}] In \texttt{cbreak} mode each input character from a terminal is directly forwarded to the
application (but see \texttt{keypad}). With \texttt{nocbreak} this only happens after a newline or return is typed.
\item[{\index{keypad@\texttt{keypad}}\texttt{keypad(win, bool)}}] If set to \texttt{true} some special input like arrow or function keys can be read as single
characters from the input (such keys actually generate certain sequences of
characters), see also \ref{ssec:ncursesInput}. (The \mbox{\texttt{\mdseries\slshape win}} argument is irrelevant.)
\item[{\index{echo@\texttt{echo}} \index{noecho@\texttt{noecho}}\texttt{echo()}/\texttt{noecho()}}] This determines if input characters are automatically echoed by the terminal
at the current cursor position.
\item[{\index{curs_set@\texttt{curs{\textunderscore}set}}\texttt{curs{\textunderscore}set(vis)}}] This determines the visibility of the cursor. The argument \mbox{\texttt{\mdseries\slshape vis}}=0 makes the cursor invisible. With \mbox{\texttt{\mdseries\slshape vis}}=1 it becomes visible; some terminals allow also higher levels of visibility.
\item[{\index{wtimeout@\texttt{wtimeout}}\texttt{wtimeout(win, delay)}}] Here \mbox{\texttt{\mdseries\slshape delay}} determines a timeout in milliseconds for reading characters from the input of
a window. Negative values mean infinity, that is a blocking read.
\item[{\index{nonl@\texttt{nonl}} \index{nl@\texttt{nl}}\texttt{nl()}/\texttt{nonl()}}] With \texttt{nl} a return on input is translated to a newline character and a newline on output
is interpreted as return and linefeed.
\item[{\index{intrflush@\texttt{intrflush}}\texttt{intrflush(win, bool)}}] This flag determines if after an interrupt pending output to the terminal is
flushed. (The \mbox{\texttt{\mdseries\slshape win}} argument is irrelevant.)
\item[{\index{idlok@\texttt{idlok}}\texttt{idlok(win, bool)}}] With \texttt{true} the library tries to use a hardware line insertion functionality (in
particular for scrolling).
\item[{\index{scrollok@\texttt{scrollok}}\texttt{scrollok(win, bool)}}] If set to \texttt{true} moving the cursor down from the last line of a window causes scrolling of the
whole window, otherwise nothing happens.
\item[{\index{leaveok@\texttt{leaveok}}\texttt{leaveok(win, bool)}}] If set to \texttt{true} a refresh of the window leaves the cursor at its current location, otherwise
this is not guaranteed.
\item[{\index{clearok@\texttt{clearok}}\texttt{clearok(win, bool)}}] If set to \texttt{true} the next refresh of the window will clear the screen completely and redraw
everything.
\item[{\index{immedok@\texttt{immedok}}\texttt{immedok(win, bool)}}] If set to \texttt{true} all changes of the window will automatically also call a \texttt{wrefresh}.
\item[{\index{noraw@\texttt{noraw}} \index{raw@\texttt{raw}}\texttt{raw()}/\texttt{noraw()}}] Similar to \texttt{cbreak}, usually not needed (see the \texttt{ncurses} documentation for details).
\end{description}
}
\subsection{\textcolor{Chapter }{Manipulating windows}}\label{ssec:ncursesWin}
\logpage{[ 2, 1, 2 ]}
\hyperdef{L}{X800D5B6381F0356F}{}
{
In \texttt{ncurses} an arbitrary number of windows which correspond to rectangular regions (maybe
overlapping) of the screen can be handled. You should always delete windows
which are no longer needed. To get a proper display of overlapping windows
(which may occur by recursively called functions using this library) we
suggest that you always wrap windows in panels, see \ref{ssec:ncursesPan}.
For functions which involve coordinates recall that the upper left corner of
the screen or internally of any window has the coordinates (0,0).
\begin{description}
\item[{\index{newwin@\texttt{newwin}}\texttt{newwin(nlines, ncols, y, x)}}] This creates a new window whose upper left corner has the coordinates (\mbox{\texttt{\mdseries\slshape y}},\mbox{\texttt{\mdseries\slshape x}}) on the screen and has \mbox{\texttt{\mdseries\slshape nlines}} lines and \mbox{\texttt{\mdseries\slshape ncols}} columns, if this is possible. The arguments \mbox{\texttt{\mdseries\slshape nlines}} and \mbox{\texttt{\mdseries\slshape ncols}} can be zero, then their maximal possible values are assumed.
\item[{\index{delwin@\texttt{delwin}}\texttt{delwin(win)}}] Deletes a window.
\item[{\index{mvwin@\texttt{mvwin}}\texttt{mvwin(win, y, x)}}] Moves the upper left corner of the window to the given coordinates, if the
window still fits on the screen. With panels don't use this function, but use \texttt{move{\textunderscore}panel} mentioned below.
\item[{\index{wrefresh@\texttt{wrefresh}}\texttt{wrefresh(win)}}] Writing to a window only changes some internal buffers, this function copies
the window content to the actual display screen. You don't need this function
if you wrap your windows in panels, use \texttt{update{\textunderscore}panels} and \texttt{doupdate} instead.
\item[{\index{doupdate@\texttt{doupdate}}\texttt{doupdate()}}] Use this function to update the content of your display screen to the current
content of all windows. If your terminal is not yet in visual mode this
function changes to visual mode.
\item[{\index{endwin@\texttt{endwin}}\texttt{endwin()}}] Use this function to leave the visual mode of your terminal. (Remark: If you
use this function while not in visual mode the cursor will be moved to the
line where the visual mode was started last time. To avoid this use \texttt{isendwin} first.)
\item[{\index{isendwin@\texttt{isendwin}}\texttt{isendwin()}}] Returns \texttt{true} if called while not in visual mode and \texttt{false} otherwise
\item[{\index{getbegyx@\texttt{getbegyx}}\texttt{getbegyx(win)}}] Get the coordinates of the upper left corner of a window on the screen.
\item[{\index{getmaxyx@\texttt{getmaxyx}}\texttt{getmaxyx(win)}}] Get the number of lines and columns of a window.
\end{description}
}
\subsection{\textcolor{Chapter }{Manipulating panels}}\label{ssec:ncursesPan}
\logpage{[ 2, 1, 3 ]}
\hyperdef{L}{X7D541BDE7BB8BED5}{}
{
Wrap windows in panels to get a proper handling of overlapping windows on the
display. Don't forget to delete a panel before deleting the corresponding
window.
\begin{description}
\item[{\index{new_panel@\texttt{new{\textunderscore}panel}}\texttt{new{\textunderscore}panel(win)}}] Create a panel for a window.
\item[{\index{del_panel@\texttt{del{\textunderscore}panel}}\texttt{del{\textunderscore}panel(pan)}}] Delete a panel.
\item[{\index{update_panels@\texttt{update{\textunderscore}panels}}\texttt{update{\textunderscore}panels()}}] Use this function to copy changes of windows and panels to a screen buffer.
Then call \texttt{doupdate()} to update the display screen.
\item[{\index{move_panel@\texttt{move{\textunderscore}panel}}\texttt{move{\textunderscore}panel(pan, y, x)}}] Move top left corner of a panel wrapped window to coordinates (\mbox{\texttt{\mdseries\slshape y}},\mbox{\texttt{\mdseries\slshape x}}) if possible.
\item[{\index{show_panel@\texttt{show{\textunderscore}panel}} \index{hide_panel@\texttt{hide{\textunderscore}panel}}\texttt{hide{\textunderscore}panel(pan)}/\texttt{show{\textunderscore}panel(pan)}}] Hide or show, respectively, the content of a panel on the display screen.
\item[{\index{bottom_panel@\texttt{bottom{\textunderscore}panel}} \index{top_panel(@\texttt{top{\textunderscore}panel}}\texttt{top{\textunderscore}panel(pan)}/\texttt{bottom{\textunderscore}panel(pan)}}] Move a panel to the top or bottom of all panels, respectively.
\item[{\index{panel_above@\texttt{panel{\textunderscore}above}} \index{panel_below@\texttt{panel{\textunderscore}below}}\texttt{panel{\textunderscore}below(pan)}/\texttt{panel{\textunderscore}above(pan)}}] Return the panel directly below or above the given one, respectively. With
argument \texttt{0} the top or bottom panel are returned, respectively. If argument is the bottom
or top panel, respectively, then \texttt{false} is returned.
\end{description}
}
\subsection{\textcolor{Chapter }{Getting keyboard input}}\label{ssec:ncursesInput}
\logpage{[ 2, 1, 4 ]}
\hyperdef{L}{X7F23F5F48650A78B}{}
{
If you want to read input from the user first adjust the terminal settings of \texttt{cbreak}, \texttt{keypad}, \texttt{echo}, \texttt{wtimeout} and \texttt{curs{\textunderscore}set} to your needs, see \ref{ssec:ncursesTermset}. The basic functions are as follows.
\begin{description}
\item[{\index{wgetch@\texttt{wgetch}}\texttt{wgetch(win)}}] Reads one character from user input (returned as integer). If \texttt{wtimeout} was set with a positive \mbox{\texttt{\mdseries\slshape delay}} then the function returns \texttt{false} if there was no input for \mbox{\texttt{\mdseries\slshape delay}} milliseconds. Note that in \texttt{nocbreak} mode typed characters reach the application only after typing a return. If the \texttt{keypad} flag is set to \texttt{true} some special keys can be read like single characters; the keys are explained
below. (Note that there is only one input queue for all windows.)
\item[{\index{ungetch@\texttt{ungetch}}\texttt{ungetch(char)}}] Puts back the character \mbox{\texttt{\mdseries\slshape char}} on the input queue.
\end{description}
\index{NCurses.keys@\texttt{NCurses.keys}} Some terminals allow one to read special keys like one character, we import
some of the symbolic names of such keys into \textsf{GAP}. You can check for such characters by comparing with the components of the
record \texttt{NCurses.keys}, these are
\begin{description}
\item[{\texttt{UP}/\texttt{DOWN}/\texttt{LEFT}/\texttt{RIGHT}}] the arrow keys
\item[{\texttt{PPAGE}/\texttt{NPAGE}}] the page up and page down keys
\item[{\texttt{HOME}/\texttt{END}}] the home and end keys
\item[{\texttt{BACKSPACE}/\texttt{DC}}] the backspace and delete keys
\item[{\texttt{IC}}] the insert key
\item[{\texttt{ENTER}}] the enter key
\item[{\texttt{F1}/\texttt{F2}/../\texttt{F24}}] the function keys
\item[{\texttt{MOUSE}}] a pseudo key to detect mouse events
\item[{\texttt{A1}/\texttt{A3}/\texttt{B2}/\texttt{C1}/\texttt{C3}}] the keys around the arrow keys on a num pad
\end{description}
It can happen that on a specific keyboard there is no key for some of these.
Also, not all terminals can interpret all of these keys. You can check this
with the function
\begin{description}
\item[{\index{has_key@\texttt{has{\textunderscore}key}}\texttt{has{\textunderscore}key(key)}}] Checks if the special key \mbox{\texttt{\mdseries\slshape key}} is recognized by the terminal.
\end{description}
}
\subsection{\textcolor{Chapter }{Writing to windows}}\label{ssec:ncursesWrite}
\logpage{[ 2, 1, 5 ]}
\hyperdef{L}{X7FD4E558816B3146}{}
{
The display of text in \texttt{ncurses} windows has two aspects. The first is to get actual characters on the screen.
The second is to specify attributes which influence the display, for example
normal or bold fonts or colors. This subsection is for the first aspect.
Possible attributes are explained below in \ref{ssec:ncursesAttrs}.
\begin{description}
\item[{\index{wmove@\texttt{wmove}}\texttt{wmove(win, y, x)}}] Moves the cursor to position (\mbox{\texttt{\mdseries\slshape y}},\mbox{\texttt{\mdseries\slshape x}}), recall that the coordinates are zero based, (0,0) being the top left
corner.
\item[{\index{waddnstr@\texttt{waddnstr}}\texttt{waddnstr(win, str, len)}}] Writes the string \mbox{\texttt{\mdseries\slshape str}} to the window starting from the current cursor position. Writes at most \mbox{\texttt{\mdseries\slshape len}} characters. At end of line the cursor moves to the beginning of next line. The
behavior at the end of the window depends on the setting of \texttt{scrollok}, see \ref{ssec:ncursesTermset}.
\item[{\index{waddch@\texttt{waddch}}\texttt{waddch(win, char)}}] Writes a character to the window at the current cursor position and moves the
cursor on. The character \mbox{\texttt{\mdseries\slshape char}} is given as integer and can include attribute information.
\item[{\index{wborder@\texttt{wborder}}\texttt{wborder(win, charlist)}}] Draws a border around the window. If \mbox{\texttt{\mdseries\slshape charlist}} is a plain list of eight \textsf{GAP} characters these are taken for left/right/top/bottom sides and
top-left/top-right/bottom-left/bottom-right corners. Otherwise default
characters are used. (See \texttt{NCurses.WBorder} (\ref{NCurses.WBorder}) for a more user friendly interface.)
\item[{\index{wvline@\texttt{wvline}}\texttt{wvline(win, char, len)}}] Writes a vertical line of length \mbox{\texttt{\mdseries\slshape len}} (or as long as fitting into the window) starting from the current cursor
position to the bottom, using the character \mbox{\texttt{\mdseries\slshape char}}. If \mbox{\texttt{\mdseries\slshape char}}=\texttt{0} the default character is used.
\item[{\index{whline@\texttt{whline}}\texttt{whline(win, char, len)}}] Same as \texttt{wvline} but for horizontal lines starting from the cursor position to the right.
\item[{\index{werase@\texttt{werase}}\texttt{werase(win)}}] Deletes all characters in the window.
\item[{\index{wclear@\texttt{wclear}}\texttt{wclear(win)}}] Like \texttt{werase}, but also calls \texttt{clearok}.
\item[{\index{wclrtobot@\texttt{wclrtobot}}\texttt{wclrtobot(win)}}] Deletes all characters from cursor position to the right and bottom.
\item[{\index{wclrtoeol@\texttt{wclrtoeol}}\texttt{wclrtoeol(win)}}] Deletes all characters from cursor position to end of line.
\item[{\index{winch@\texttt{winch}}\texttt{winch(win)}}] Returns the character at current cursor position, as integer and including
color and attribute information.
\item[{\index{getyx@\texttt{getyx}}\texttt{getyx(win)}}] Returns the current cursor position.
\item[{\index{waddstr@\texttt{waddstr}}\texttt{waddstr(win, str)}}] Delegates to \texttt{waddnstr(win, str, Length(str))}.
\end{description}
}
\subsection{\textcolor{Chapter }{Line drawing characters}}\label{ssec:ncursesLines}
\logpage{[ 2, 1, 6 ]}
\hyperdef{L}{X8091936586CCD248}{}
{
\index{NCurses.lineDraw@\texttt{NCurses.lineDraw}} For drawing lines and grids in a terminal window you should use some "virtual"
characters which are available as components of the record \texttt{NCurses.lineDraw}. On some terminals these are nicely displayed as proper lines (on others they
are simulated by ASCII characters). These are:
\begin{description}
\item[{\texttt{BLOCK}}] solid block
\item[{\texttt{BOARD}}] board of squares
\item[{\texttt{BTEE/LTEE/RTEE/TTEE}}] bottom/left/right/top tee
\item[{\texttt{BULLET}}] bullet
\item[{\texttt{CKBOARD}}] checker board
\item[{\texttt{DARROW/LARROW/RARROW/UARROW}}] down/left/right/up arrow
\item[{\texttt{DEGREE}}] degree symbol
\item[{\texttt{DIAMOND}}] diamond
\item[{\texttt{GEQUAL}}] greater than or equal
\item[{\texttt{HLINE/VLINE}}] horizontal/vertical line
\item[{\texttt{LANTERN}}] lantern symbol
\item[{\texttt{LEQUAL}}] less than or equal
\item[{\texttt{LLCORNER/LRCORNER/ULCORNER/URCORNER}}] lower left/lower right/upper left/upper right corner
\item[{\texttt{NEQUAL}}] not equal
\item[{\texttt{PI}}] letter pi
\item[{\texttt{PLMINUS}}] plus-minus
\item[{\texttt{PLUS}}] crossing lines like a plus
\item[{\texttt{S1/S3/S7/S9}}] scan line 1/3/7/9
\item[{\texttt{STERLING}}] pound sterling
\end{description}
}
\subsection{\textcolor{Chapter }{Text attributes and colors}}\label{ssec:ncursesAttrs}
\logpage{[ 2, 1, 7 ]}
\hyperdef{L}{X793D897483674294}{}
{
In addition to the actual characters to be written to the screen the way they
are displayed can be changed by additional \emph{attributes}. \index{attributes of text} (There should be no danger to mix up this notion of attributes with the one
introduced in{\nobreakspace} (\textbf{Reference: Attributes}).) \index{NCurses.attrs@\texttt{NCurses.attrs}} The available attributes are stored in the record \texttt{NCurses.attrs}, they are
\begin{description}
\item[{\texttt{NORMAL}}] normal display with no extra attributes.
\item[{\texttt{STANDOUT}}] displays text in the best highlighting mode of the terminal.
\item[{\texttt{UNDERLINE}}] underlines the text.
\item[{\texttt{REVERSE}}] display in reverse video by exchanging the foreground and background color.
\item[{\texttt{BLINK}}] displays the text blinking.
\item[{\texttt{DIM}}] displays the text half bright.
\item[{\texttt{BOLD}}] displays the text in a bold font.
\end{description}
Note that not all of these work with all types of terminals, or some may cause
the same display. Furthermore, if \texttt{NCurses.attrs.has{\textunderscore}colors} is \texttt{true} there is a list \texttt{NCurses.attrs.ColorPairs} of attributes to set the foreground and background color. These should be
accessed indirectly with \texttt{NCurses.ColorAttr} (\ref{NCurses.ColorAttr}). Attributes can be combined by adding their values (internally, they are
represented by integers). They can also be added to the integer representing a
character for use with \texttt{waddch}.
The library functions for setting attributes are:
\begin{description}
\item[{\index{wattrset@\texttt{wattrset}}\texttt{wattrset(win, attr)}}] This sets the default (combined) attributes for a window which is added to all
characters written to it; using \texttt{NCurses.attrs.NORMAL} as attribute is a reset.
\item[{\index{wattroff@\texttt{wattroff}} \index{wattron@\texttt{wattron}}\texttt{wattron(win, attr)}/\texttt{wattroff(win, attr)}}] This sets or unsets one or some default attributes of the window without
changing the others.
\item[{\index{wattr_get@\texttt{wattr{\textunderscore}get}}\texttt{wattr{\textunderscore}get(win)}}] This returns the current default attribute and default color pair of a window.
\item[{\index{wbkgdset@\texttt{wbkgdset}}\texttt{wbkgdset(win, attr)}}] This is similar to \texttt{wattrset} but you can also add a character to \mbox{\texttt{\mdseries\slshape attr}} which is used as default instead of blanks.
\item[{\index{wbkgd@\texttt{wbkgd}}\texttt{wbkgd(win, attr)}}] This function changes the attributes for all characters in the window to \mbox{\texttt{\mdseries\slshape attr}}, also used for further characters written to that window.
\end{description}
}
\subsection{\textcolor{Chapter }{Low level \texttt{ncurses} mouse support}}\label{ssec:ncursesMouse}
\logpage{[ 2, 1, 8 ]}
\hyperdef{L}{X86675F5F791FEFEF}{}
{
Many \texttt{xterm} based terminals support mouse events. The recognition of mouse events by the \texttt{ncurses} input queue can be switched on and off. If switched on and a mouse event
occurs, then \texttt{NCurses.wgetch} gets \texttt{NCurses.keys.MOUSE} if the \texttt{keypad} flag is \texttt{true} (see \ref{ssec:ncursesInput}). If this is read one must call \texttt{NCurses.getmouse} which reads further characters from the input queue and interprets them as
details on the mouse event. In most cases the function \texttt{NCurses.GetMouseEvent} (\ref{NCurses.GetMouseEvent}) can be used in applications (it calls \texttt{NCurses.getmouse}). The following low level functions are available as components of the record \texttt{NCurses}.
The names of mouse events which may be possible are stored in the list \texttt{NCurses.mouseEvents}, which starts \texttt{[} \texttt{"BUTTON1{\textunderscore}PRESSED",} \texttt{"BUTTON1{\textunderscore}RELEASED",} \texttt{"BUTTON1{\textunderscore}CLICKED",} \texttt{"BUTTON1{\textunderscore}DOUBLE{\textunderscore}CLICKED",} \texttt{"BUTTON1{\textunderscore}TRIPLE{\textunderscore}CLICKED",} \texttt{...} and contains the same for buttons number 2 to 5 and a few other events.
\begin{description}
\item[{\index{mousemask@\texttt{mousemask}} \texttt{mousemask(intlist)}}] The argument \mbox{\texttt{\mdseries\slshape intlist}} is a list of integers specifying mouse events. An entry \texttt{i} refers to the event described in \texttt{NCurses.mouseEvents[i+1]}. It returns a record with components \texttt{.new} (for the current setting) and \texttt{.old} (for the previous setting) which are again lists of integers with the same
meaning. Note that \texttt{.new} may be different from \mbox{\texttt{\mdseries\slshape intlist}}, it is always the empty list if the terminal does not support mouse events.
In applications use \texttt{NCurses.UseMouse} (\ref{NCurses.UseMouse}) instead of this low level function.
\item[{\index{getmouse@\texttt{getmouse}} \texttt{getmouse()}}] This function must be called after a key \texttt{NCurses.keys.MOUSE} was read. It returns a list with three entries \texttt{[y, x, intlist]} where \texttt{y} and \texttt{x} are the coordinates of the character cell where the mouse event occured and \texttt{intlist} describes the event, it should have length one and refers to a position in \texttt{NCurses.mouseEvents}.
\item[{\index{wenclose@\texttt{wenclose}} \texttt{wenclose(win, y, x)}}] This functions returns \texttt{true} if the screen position \mbox{\texttt{\mdseries\slshape y}}, \mbox{\texttt{\mdseries\slshape x}} is within window \mbox{\texttt{\mdseries\slshape win}} and \texttt{false} otherwise.
\item[{\index{mouseinterval@\texttt{mouseinterval}} \texttt{mouseinterval(t)}}] Sets the time to recognize a press and release of a mouse button as a click to \mbox{\texttt{\mdseries\slshape t}} milliseconds. (Note that this may have no effect because a window manager may
catch this.)
\end{description}
}
\subsection{\textcolor{Chapter }{Miscellaneous function}}\label{ssec:ncursesMisc}
\logpage{[ 2, 1, 9 ]}
\hyperdef{L}{X83897BF984211EFD}{}
{
\index{mnap@\texttt{mnap}} \index{IsStdinATty@\texttt{IsStdinATty}} \index{IsStdoutATty@\texttt{IsStdoutATty}} We also provide the \texttt{ncurses} function \texttt{mnap(msec)} which is a sleep for \mbox{\texttt{\mdseries\slshape msec}} milliseconds.
Furthermore, there a two utilities which can be useful for scripts and
testing, namely a check if standard input or standard output are connected to
terminals. These can be called as \texttt{NCurses.IsStdinATty()} or \texttt{NCurses.IsStdoutATty()}, respectively. }
}
\section{\textcolor{Chapter }{The \texttt{ncurses} \textsf{GAP} functions}}\label{sec:cursesGAP}
\logpage{[ 2, 2, 0 ]}
\hyperdef{L}{X864A5C1C7F181B4B}{}
{
The functions of the \texttt{ncurses} library are used within \textsf{GAP} very similarly to their \texttt{C} equivalents. The functions are available as components of a record \texttt{NCurses} with the name of the \texttt{C} function (e.g., \texttt{NCurses.newwin}).
In \textsf{GAP} the \texttt{ncurses} windows are accessed via integers (as returned by \texttt{NCurses.newwin}). The standard screen \texttt{stdscr} from the \texttt{ncurses} library is available as window number \texttt{0}. But this should not be used; to allow recursive applications of \texttt{ncurses} always create a new window, wrap it in a panel and delete both when they are
no longer needed.
Each window can be wrapped in one panel which is accessed by the same integer.
(Window \texttt{0} cannot be used with a panel.)
Coordinates in windows are the same zero based integers as in the
corresponding \texttt{C} functions. The interface of functions which \emph{return} coordinates is slightly different from the \texttt{C} version; they just return lists of integers and you just give the window as
argument, e.g., \texttt{NCurses.getmaxyx(win)} returns a list \texttt{[nrows, ncols]} of two integers.
Characters to be written to a window can be given either as \textsf{GAP} characters like \texttt{'a'} or as integers like \texttt{INT{\textunderscore}CHAR('a') = 97}. If you use the integer version you can also add attributes including color
settings to it for use with \texttt{NCurses.waddch}.
When writing an application decide about an appropriate terminal setting for
your visual mode windows, see \ref{ssec:ncursesTermset} and the utility function \texttt{NCurses.SetTerm} (\ref{NCurses.SetTerm}) below. Use \texttt{NCurses.savetty()} and \texttt{NCurses.resetty()} to save and restore the previous setting.
We also provide some higher level functionality for displaying marked up text,
see \texttt{NCurses.PutLine} (\ref{NCurses.PutLine}) and \texttt{NCurses.IsAttributeLine} (\ref{NCurses.IsAttributeLine}).
We now describe some utility functions for putting text on a terminal window.
\subsection{\textcolor{Chapter }{NCurses.ColorAttr}}
\logpage{[ 2, 2, 1 ]}\nobreak
\hyperdef{L}{X83ADB4E37C105B8C}{}
{\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{NCurses.ColorAttr({\mdseries\slshape fgcolor, bgcolor})\index{NCurses.ColorAttr@\texttt{NCurses.ColorAttr}}
\label{NCurses.ColorAttr}
}\hfill{\scriptsize (function)}}\\
\textbf{\indent Returns:\ }
an attribute for setting the foreground and background color to be used on a
terminal window (it is a \textsf{GAP} integer).
\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{NCurses.attrs.has{\textunderscore}colors\index{NCurses.attrs.has{\textunderscore}colors@\texttt{NCurses.attrs.has{\textunderscore}colors}}
\label{NCurses.attrs.hasuScorecolors}
}\hfill{\scriptsize (global variable)}}\\
The return value can be used like any other attribute as described in \ref{ssec:ncursesAttrs}. The arguments \mbox{\texttt{\mdseries\slshape fgcolor}} and \mbox{\texttt{\mdseries\slshape bgcolor}} can be given as strings, allowed are those in \texttt{[ "black", "red", "green", "yellow", "blue", "magenta", "cyan", "white" ]}. These are the default foreground colors 0 to 7 on ANSI terminals.
Alternatively, the numbers 0 to 7 can be used directly as arguments.
Note that terminals can be configured in a way such that these named colors
are not the colors which are actually displayed.
The variable \texttt{NCurses.attrs.has{\textunderscore}colors} (\ref{NCurses.attrs.hasuScorecolors}) \index{colors, availability} is set to \texttt{true} or \texttt{false} if the terminal supports colors or not, respectively. If a terminal does not
support colors then \texttt{NCurses.ColorAttr} always returns \texttt{NCurses.attrs.NORMAL}.
For an attribute setting the foreground color with the default background
color of the terminal use \texttt{-1} as \mbox{\texttt{\mdseries\slshape bgcolor}} or the same as \mbox{\texttt{\mdseries\slshape fgcolor}}.
\begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=Example]
!gapprompt@gap>| !gapinput@win := NCurses.newwin(0,0,0,0);; pan := NCurses.new_panel(win);;|
!gapprompt@gap>| !gapinput@defc := NCurses.defaultColors;;|
!gapprompt@gap>| !gapinput@NCurses.wmove(win, 0, 0);;|
!gapprompt@gap>| !gapinput@for a in defc do for b in defc do|
!gapprompt@>| !gapinput@ NCurses.wattrset(win, NCurses.ColorAttr(a, b));|
!gapprompt@>| !gapinput@ NCurses.waddstr(win, Concatenation(a,"/",b,"\t"));|
!gapprompt@>| !gapinput@ od; od;|
!gapprompt@gap>| !gapinput@if NCurses.IsStdoutATty() then|
!gapprompt@>| !gapinput@ NCurses.update_panels();; NCurses.doupdate();;|
!gapprompt@>| !gapinput@ NCurses.napms(5000);; # show for 5 seconds|
!gapprompt@>| !gapinput@ NCurses.endwin();; NCurses.del_panel(pan);; NCurses.delwin(win);;|
!gapprompt@>| !gapinput@ fi;|
\end{Verbatim}
}
\subsection{\textcolor{Chapter }{NCurses.SetTerm}}
\logpage{[ 2, 2, 2 ]}\nobreak
\hyperdef{L}{X879D81B37A0A4E8F}{}
{\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{NCurses.SetTerm({\mdseries\slshape [record]})\index{NCurses.SetTerm@\texttt{NCurses.SetTerm}}
\label{NCurses.SetTerm}
}\hfill{\scriptsize (function)}}\\
This function provides a unified interface to the various terminal setting
functions of \texttt{ncurses} listed in \ref{ssec:ncursesTermset}. The optional argument is a record with components which are assigned to \texttt{true} or \texttt{false}. Recognised components are: \texttt{cbreak}, \texttt{echo}, \texttt{nl}, \texttt{intrflush}, \texttt{leaveok}, \texttt{scrollok}, \texttt{keypad}, \texttt{raw} (with the obvious meaning if set to \texttt{true} or \texttt{false}, respectively).
The default, if no argument is given, is \texttt{rec(cbreak := true, echo := false, nl := false, intrflush := false, leaveok :=
true, scrollok := false, keypad := true)}. (This is a useful setting for many applications.) If there is an argument \mbox{\texttt{\mdseries\slshape record}}, then the given components overwrite the corresponding defaults. }
\subsection{\textcolor{Chapter }{NCurses.IsAttributeLine}}
\logpage{[ 2, 2, 3 ]}\nobreak
\hyperdef{L}{X81D1FC927C455AEB}{}
{\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{NCurses.IsAttributeLine({\mdseries\slshape obj})\index{NCurses.IsAttributeLine@\texttt{NCurses.IsAttributeLine}}
\label{NCurses.IsAttributeLine}
}\hfill{\scriptsize (function)}}\\
\textbf{\indent Returns:\ }
\texttt{true} if the argument describes a string with attributes.
An \emph{attribute line} describes a string with attributes. It is represented by either a string or a
dense list of strings, integers, and Booleans immediately following integers,
where at least one list entry must \emph{not} be a string. (The reason is that we want to be able to distinguish between an
attribute line and a list of such lines, and that the case of plain strings is
perhaps the most usual one, so we do not want to force wrapping each string in
a list.) The integers denote attribute values such as color or font
information, the Booleans denote that the attribute given by the preceding
integer is set or reset.
If an integer is not followed by a Boolean then it is used as the attribute
for the following characters, that is it overwrites all previously set
attributes. Note that in some applications the variant with explicit Boolean
values is preferable, because such a line can nicely be highlighted just by
prepending a \texttt{NCurses.attrs.STANDOUT} attribute.
For an overview of attributes, see{\nobreakspace}\ref{ssec:ncursesAttrs}.
\begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=Example]
!gapprompt@gap>| !gapinput@NCurses.IsAttributeLine( "abc" );|
true
!gapprompt@gap>| !gapinput@NCurses.IsAttributeLine( [ "abc", "def" ] );|
false
!gapprompt@gap>| !gapinput@NCurses.IsAttributeLine( [ NCurses.attrs.UNDERLINE, true, "abc" ] );|
true
!gapprompt@gap>| !gapinput@NCurses.IsAttributeLine( "" ); NCurses.IsAttributeLine( [] );|
true
false
\end{Verbatim}
The \emph{empty string} is an attribute line whereas the \emph{empty list} (which is not in \texttt{IsStringRep} (\textbf{Reference: IsStringRep})) is \emph{not} an attribute line. }
\subsection{\textcolor{Chapter }{NCurses.ConcatenationAttributeLines}}
\logpage{[ 2, 2, 4 ]}\nobreak
\hyperdef{L}{X8372F0C57816A29E}{}
{\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{NCurses.ConcatenationAttributeLines({\mdseries\slshape lines[, keep]})\index{NCurses.ConcatenationAttributeLines@\texttt{NCurses.ConcatenationAttributeLines}}
\label{NCurses.ConcatenationAttributeLines}
}\hfill{\scriptsize (function)}}\\
\textbf{\indent Returns:\ }
an attribute line.
For a list \mbox{\texttt{\mdseries\slshape lines}} of attribute lines (see \texttt{NCurses.IsAttributeLine} (\ref{NCurses.IsAttributeLine})), \texttt{NCurses.ConcatenationAttributeLines} returns the attribute line obtained by concatenating the attribute lines in \mbox{\texttt{\mdseries\slshape lines}}.
If the optional argument \mbox{\texttt{\mdseries\slshape keep}} is \texttt{true} then attributes set in an entry of \mbox{\texttt{\mdseries\slshape lines}} are valid also for the following entries of \mbox{\texttt{\mdseries\slshape lines}}. Otherwise (in particular if there is no second argument) the attributes are
reset to \texttt{NCurses.attrs.NORMAL} between the entries of \mbox{\texttt{\mdseries\slshape lines}}.
\begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=Example]
!gapprompt@gap>| !gapinput@plain_str:= "hello";;|
!gapprompt@gap>| !gapinput@with_attr:= [ NCurses.attrs.BOLD, "bold" ];;|
!gapprompt@gap>| !gapinput@NCurses.ConcatenationAttributeLines( [ plain_str, plain_str ] );|
"hellohello"
!gapprompt@gap>| !gapinput@NCurses.ConcatenationAttributeLines( [ plain_str, with_attr ] );|
[ "hello", 2097152, "bold" ]
!gapprompt@gap>| !gapinput@NCurses.ConcatenationAttributeLines( [ with_attr, plain_str ] );|
[ 2097152, "bold", 0, "hello" ]
!gapprompt@gap>| !gapinput@NCurses.ConcatenationAttributeLines( [ with_attr, with_attr ] );|
[ 2097152, "bold", 0, 2097152, "bold" ]
!gapprompt@gap>| !gapinput@NCurses.ConcatenationAttributeLines( [ with_attr, with_attr ], true );|
[ 2097152, "bold", 2097152, "bold" ]
\end{Verbatim}
}
\subsection{\textcolor{Chapter }{NCurses.RepeatedAttributeLine}}
\logpage{[ 2, 2, 5 ]}\nobreak
\hyperdef{L}{X7D2EB0BF82C4F25C}{}
{\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{NCurses.RepeatedAttributeLine({\mdseries\slshape line, width})\index{NCurses.RepeatedAttributeLine@\texttt{NCurses.RepeatedAttributeLine}}
\label{NCurses.RepeatedAttributeLine}
}\hfill{\scriptsize (function)}}\\
\textbf{\indent Returns:\ }
an attribute line.
For an attribute line \mbox{\texttt{\mdseries\slshape line}} (see \texttt{NCurses.IsAttributeLine} (\ref{NCurses.IsAttributeLine})) and a positive integer \mbox{\texttt{\mdseries\slshape width}}, \texttt{NCurses.RepeatedAttributeLine} returns an attribute line with \mbox{\texttt{\mdseries\slshape width}} displayed characters (see{\nobreakspace}\texttt{NCurses.WidthAttributeLine} (\ref{NCurses.WidthAttributeLine})) that is obtained by concatenating sufficiently many copies of \mbox{\texttt{\mdseries\slshape line}} and cutting off a tail if applicable.
\begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=Example]
!gapprompt@gap>| !gapinput@NCurses.RepeatedAttributeLine( "12345", 23 );|
"12345123451234512345123"
!gapprompt@gap>| !gapinput@NCurses.RepeatedAttributeLine( [ NCurses.attrs.BOLD, "12345" ], 13 );|
[ 2097152, "12345", 0, 2097152, "12345", 0, 2097152, "123" ]
\end{Verbatim}
}
\subsection{\textcolor{Chapter }{NCurses.PutLine}}
\logpage{[ 2, 2, 6 ]}\nobreak
\hyperdef{L}{X83FFD5047ADE716E}{}
{\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{NCurses.PutLine({\mdseries\slshape win, y, x, lines[, skip]})\index{NCurses.PutLine@\texttt{NCurses.PutLine}}
\label{NCurses.PutLine}
}\hfill{\scriptsize (function)}}\\
\textbf{\indent Returns:\ }
\texttt{true} if \mbox{\texttt{\mdseries\slshape lines}} were written, otherwise \texttt{false}.
The argument \mbox{\texttt{\mdseries\slshape lines}} can be a list of attribute lines (see \texttt{NCurses.IsAttributeLine} (\ref{NCurses.IsAttributeLine})) or a single attribute line. This function writes the attribute lines to
window \mbox{\texttt{\mdseries\slshape win}} at and below of position \mbox{\texttt{\mdseries\slshape y}}, \mbox{\texttt{\mdseries\slshape x}}.
If the argument \mbox{\texttt{\mdseries\slshape skip}} is given, it must be a nonnegative integer. In that case the first \mbox{\texttt{\mdseries\slshape skip}} characters of each given line are not written to the window (but the
attributes are). }
\subsection{\textcolor{Chapter }{NCurses.WidthAttributeLine}}
\logpage{[ 2, 2, 7 ]}\nobreak
\hyperdef{L}{X82C53ACD805EE0C3}{}
{\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{NCurses.WidthAttributeLine({\mdseries\slshape line})\index{NCurses.WidthAttributeLine@\texttt{NCurses.WidthAttributeLine}}
\label{NCurses.WidthAttributeLine}
}\hfill{\scriptsize (function)}}\\
\textbf{\indent Returns:\ }
number of displayed characters in an attribute line.
For an attribute line \mbox{\texttt{\mdseries\slshape line}} (see \texttt{NCurses.IsAttributeLine} (\ref{NCurses.IsAttributeLine})), the function returns the number of displayed characters of \mbox{\texttt{\mdseries\slshape line}}. \index{displayed characters}
\begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=Example]
!gapprompt@gap>| !gapinput@NCurses.WidthAttributeLine( "abcde" );|
5
!gapprompt@gap>| !gapinput@NCurses.WidthAttributeLine( [ NCurses.attrs.BOLD, "abc",|
!gapprompt@>| !gapinput@ NCurses.attrs.NORMAL, "de" ] );|
5
\end{Verbatim}
}
\subsection{\textcolor{Chapter }{NCurses.Grid}}
\logpage{[ 2, 2, 8 ]}\nobreak
\hyperdef{L}{X790715F683BF1E66}{}
{\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{NCurses.Grid({\mdseries\slshape win, trow, brow, lcol, rcol, rowinds, colinds})\index{NCurses.Grid@\texttt{NCurses.Grid}}
\label{NCurses.Grid}
}\hfill{\scriptsize (function)}}\\
This function draws a grid of horizontal and vertical lines on the window \mbox{\texttt{\mdseries\slshape win}}, using the line drawing characters explained in \ref{ssec:ncursesLines}. The given arguments specify the top and bottom row of the grid, its left and
right column, and lists of row and column numbers where lines should be drawn.
\begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=Example]
!gapprompt@gap>| !gapinput@fun := function() local win, pan;|
!gapprompt@>| !gapinput@ win := NCurses.newwin(0,0,0,0);|
!gapprompt@>| !gapinput@ pan := NCurses.new_panel(win);|
!gapprompt@>| !gapinput@ NCurses.Grid(win, 2, 11, 5, 22, [5, 6], [13, 14]);|
!gapprompt@>| !gapinput@ NCurses.PutLine(win, 12, 0, "Press <Enter> to quit");|
!gapprompt@>| !gapinput@ NCurses.update_panels(); NCurses.doupdate();|
!gapprompt@>| !gapinput@ NCurses.wgetch(win);|
!gapprompt@>| !gapinput@ NCurses.endwin();|
!gapprompt@>| !gapinput@ NCurses.del_panel(pan); NCurses.delwin(win);|
!gapprompt@>| !gapinput@end;;|
!gapprompt@gap>| !gapinput@fun();|
\end{Verbatim}
}
\subsection{\textcolor{Chapter }{NCurses.WBorder}}
\logpage{[ 2, 2, 9 ]}\nobreak
\hyperdef{L}{X82B801587B37D571}{}
{\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{NCurses.WBorder({\mdseries\slshape win[, chars]})\index{NCurses.WBorder@\texttt{NCurses.WBorder}}
\label{NCurses.WBorder}
}\hfill{\scriptsize (function)}}\\
This is a convenient interface to the \texttt{ncurses} function \texttt{wborder}. It draws a border around the window \mbox{\texttt{\mdseries\slshape win}}. If no second argument is given the default line drawing characters are used,
see \ref{ssec:ncursesLines}. Otherwise, \mbox{\texttt{\mdseries\slshape chars}} must be a list of \textsf{GAP} characters or integers specifying characters, possibly with attributes. If \mbox{\texttt{\mdseries\slshape chars}} has length 8 the characters are used for the left/right/top/bottom sides and
top-left/top-right/bottom-left/bottom-right corners. If \mbox{\texttt{\mdseries\slshape chars}} contains 2 characters the first is used for the sides and the second for all
corners. If \mbox{\texttt{\mdseries\slshape chars}} contains just one character it is used for all sides including the corners. }
\subsection{\textcolor{Chapter }{Mouse support in \texttt{ncurses} applications}}\logpage{[ 2, 2, 10 ]}
\hyperdef{L}{X799C033A7AB582D7}{}
{
\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{NCurses.UseMouse({\mdseries\slshape on})\index{NCurses.UseMouse@\texttt{NCurses.UseMouse}}
\label{NCurses.UseMouse}
}\hfill{\scriptsize (function)}}\\
\textbf{\indent Returns:\ }
a record
\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{NCurses.GetMouseEvent({\mdseries\slshape })\index{NCurses.GetMouseEvent@\texttt{NCurses.GetMouseEvent}}
\label{NCurses.GetMouseEvent}
}\hfill{\scriptsize (function)}}\\
\textbf{\indent Returns:\ }
a list of records
\texttt{ncurses} allows on some terminals (\texttt{xterm} and related) to catch mouse events. In principle a subset of events can be
caught, see \texttt{mousemask} in \ref{ssec:ncursesMouse}. But this does not seem to work well with proper subsets of possible events
(probably due to intermediate processes X, window manager, terminal
application, ...). Therefore we suggest to catch either all or no mouse events
in applications.
This can be done with \texttt{NCurses.UseMouse} with argument \texttt{true} to switch on the recognition of mouse events and \texttt{false} to switch it off. The function returns a record with components \texttt{.new} and \texttt{.old} which are both set to the status \texttt{true} or \texttt{false} from after and before the call, respectively. (There does not seem to be a
possibility to get the current status without calling \texttt{NCurses.UseMouse}.) If you call the function with argument \texttt{true} and the \texttt{.new} component of the result is \texttt{false}, then the terminal does not support mouse events.
When the recognition of mouse events is switched on and a mouse event occurs
then the key \texttt{NCurses.keys.MOUSE} is found in the input queue, see \texttt{wgetch} in \ref{ssec:ncursesInput}. If this key is read the low level function \texttt{NCurses.getmouse} must be called to fetch further details about the event from the input queue,
see \ref{ssec:ncursesMouse}. In many cases this can be done by calling the function \texttt{NCurses.GetMouseEvent} which also generates additional information. The return value is a list of
records, one for each panel over which the event occured, these panels sorted
from top to bottom (so, often you will just need the first entry if there is
any). Each of these records has components \texttt{.win}, the corresponding window of the panel, \texttt{.y} and \texttt{.x}, the relative coordinates in window \texttt{.win} where the event occured, and \texttt{.event}, which is bound to one of the strings in \texttt{NCurses.mouseEvents} which describes the event.
\emph{Suggestion:} Always make the use of the mouse optional in your application. Allow the user
to switch mouse usage on and off while your application is running. Some users
may not like to give mouse control to your application, for example the
standard cut and paste functionality cannot be used while mouse events are
caught. }
\subsection{\textcolor{Chapter }{NCurses.SaveWin}}
\logpage{[ 2, 2, 11 ]}\nobreak
\hyperdef{L}{X85FB1D7878A322EB}{}
{\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{NCurses.SaveWin({\mdseries\slshape win})\index{NCurses.SaveWin@\texttt{NCurses.SaveWin}}
\label{NCurses.SaveWin}
}\hfill{\scriptsize (function)}}\\
\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{NCurses.StringsSaveWin({\mdseries\slshape cont})\index{NCurses.StringsSaveWin@\texttt{NCurses.StringsSaveWin}}
\label{NCurses.StringsSaveWin}
}\hfill{\scriptsize (function)}}\\
\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{NCurses.RestoreWin({\mdseries\slshape win, cont})\index{NCurses.RestoreWin@\texttt{NCurses.RestoreWin}}
\label{NCurses.RestoreWin}
}\hfill{\scriptsize (function)}}\\
\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{NCurses.ShowSaveWin({\mdseries\slshape cont})\index{NCurses.ShowSaveWin@\texttt{NCurses.ShowSaveWin}}
\label{NCurses.ShowSaveWin}
}\hfill{\scriptsize (function)}}\\
\textbf{\indent Returns:\ }
a \textsf{GAP} object describing the contents of a window.
These functions can be used to save and restore the contents of \texttt{ncurses} windows. \texttt{NCurses.SaveWin} returns a list \texttt{[nrows, ncols, chars]} giving the number of rows, number of columns, and a list of integers
describing the content of window \mbox{\texttt{\mdseries\slshape win}}. The integers in the latter contain the displayed characters plus the
attributes for the display.
The function \texttt{NCurses.StringsSaveWin} translates data \mbox{\texttt{\mdseries\slshape cont}} in form of the output of \texttt{NCurses.SaveWin} to a list of \texttt{nrows} strings giving the text of the rows of the saved window, and ignoring the
attributes. You can view the result with \texttt{NCurses.Pager} (\ref{NCurses.Pager}).
The argument \mbox{\texttt{\mdseries\slshape cont}} for \texttt{NCurses.RestoreWin} must be of the same format as the output of \texttt{NCurses.SaveWin}. The content of the saved window is copied to the window \mbox{\texttt{\mdseries\slshape win}}, starting from the top-left corner as much as it fits.
The utility \texttt{NCurses.ShowSaveWin} can be used to display the output of \texttt{NCurses.SaveWin} (as much of the top-left corner as fits on the screen). }
}
}
\chapter{\textcolor{Chapter }{Utilities using \texttt{ncurses}}}\label{ch:util}
\logpage{[ 3, 0, 0 ]}
\hyperdef{L}{X7F3A63788200AB4F}{}
{
In this chapter we describe the usage of some example applications of the \texttt{ncurses} interface provided by the \textsf{Browse} package. They may be of interest by themselves, or they may be used as utility
functions within larger applications.
\section{\textcolor{Chapter }{\texttt{ncurses} utilities}}\label{sect:ncurses_utils}
\logpage{[ 3, 1, 0 ]}
\hyperdef{L}{X84E621798148857D}{}
{
If you call the functions \texttt{NCurses.Alert} (\ref{NCurses.Alert}), \texttt{NCurses.Select} (\ref{NCurses.Select}), \texttt{NCurses.GetLineFromUser} (\ref{NCurses.GetLineFromUser}), or \texttt{NCurses.Pager} (\ref{NCurses.Pager}) from another \texttt{ncurses} application in visual mode, you should refresh the windows that are still
open, by calling \texttt{NCurses.update{\textunderscore}panels} and \texttt{NCurses.doupdate} afterwards, see Section \ref{ssec:ncursesPan} and \ref{ssec:ncursesWin}. Also, if the cursor shall be hidden after that, you should call \texttt{curs{\textunderscore}set} with argument \texttt{0}, see Section \ref{ssec:ncursesTermset}, since the cursor is automatically made visible in \texttt{NCurses.endwin}.
\subsection{\textcolor{Chapter }{NCurses.Alert}}
\logpage{[ 3, 1, 1 ]}\nobreak
\hyperdef{L}{X83E95B4A83BC473E}{}
{\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{NCurses.Alert({\mdseries\slshape messages, timeout[, attrs]})\index{NCurses.Alert@\texttt{NCurses.Alert}}
\label{NCurses.Alert}
}\hfill{\scriptsize (function)}}\\
\textbf{\indent Returns:\ }
the integer corresponding to the character entered, or \texttt{fail}.
In visual mode, \texttt{Print} (\textbf{Reference: Print}) cannot be used for messages. An alternative is given by \texttt{NCurses.Alert}.
Let \mbox{\texttt{\mdseries\slshape messages}} be either an attribute line or a nonempty list of attribute lines, and \mbox{\texttt{\mdseries\slshape timeout}} be a nonnegative integer. \texttt{NCurses.Alert} shows \mbox{\texttt{\mdseries\slshape messages}} in a bordered box in the middle of the screen.
If \mbox{\texttt{\mdseries\slshape timeout}} is zero then the box is closed after any user input, and the integer
corresponding to the entered key is returned. If \mbox{\texttt{\mdseries\slshape timeout}} is a positive number $n$, say, then the box is closed after $n$ milliseconds, and \texttt{fail} is returned.
If \texttt{timeout} is zero and mouse events are enabled (see \texttt{NCurses.UseMouse} (\ref{NCurses.UseMouse}))\index{mouse events} then the box can be moved inside the window via mouse events.
If the optional argument \mbox{\texttt{\mdseries\slshape attrs}} is given, it must be an integer representing attributes such as the components
of \texttt{NCurses.attrs} (see Section{\nobreakspace}\ref{ssec:ncursesAttrs}) or the return value of \texttt{NCurses.ColorAttr} (\ref{NCurses.ColorAttr}); these attributes are used for the border of the box. The default is \texttt{NCurses.attrs.NORMAL}.
\begin{Verbatim}[commandchars=@|E,fontsize=\small,frame=single,label=Example]
@gapprompt|gap>E @gapinput|NCurses.Alert( "Hello world!", 1000 );E
fail
@gapprompt|gap>E @gapinput|NCurses.Alert( [ "Hello world!",E
@gapprompt|>E @gapinput| [ "Hello ", NCurses.attrs.BOLD, "bold!" ] ], 1500,E
@gapprompt|>E @gapinput| NCurses.ColorAttr( "red", -1 ) + NCurses.attrs.BOLD );E
fail
\end{Verbatim}
}
\subsection{\textcolor{Chapter }{NCurses.Select}}
\logpage{[ 3, 1, 2 ]}\nobreak
\hyperdef{L}{X833D321E86528981}{}
{\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{NCurses.Select({\mdseries\slshape poss[, single[, none]]})\index{NCurses.Select@\texttt{NCurses.Select}}
\label{NCurses.Select}
}\hfill{\scriptsize (function)}}\\
\textbf{\indent Returns:\ }
Position or list of positions, or \texttt{false}.
\index{checkbox!see NCurses.Select} \index{radio button!see NCurses.Select} This function allows the user to select one or several items from a given
list. In the simplest case \mbox{\texttt{\mdseries\slshape poss}} is a list of attribute lines (see \texttt{NCurses.IsAttributeLine} (\ref{NCurses.IsAttributeLine})), each of which should fit on one line. Then \texttt{NCurses.Select} displays these lines and lets the user browse through them. After pressing the \textsc{Return} key the index of the highlighted item is returned. Note that attributes in
your lines should be switched on and off separately by \texttt{true}/\texttt{false} entries such that the lines can be nicely highlighted.
The optional argument \mbox{\texttt{\mdseries\slshape single}} must be \texttt{true} (default) or \texttt{false}. In the second case, an arbitrary number of items can be marked and the
function returns the list of their indices.
If \mbox{\texttt{\mdseries\slshape single}} is \texttt{true} a third argument \mbox{\texttt{\mdseries\slshape none}} can be given. If it is \texttt{true} then it is possible to leave the selection without choosing an item, in this
case \texttt{false} is returned.
More details can be given to the function by giving a record as argument \mbox{\texttt{\mdseries\slshape poss}}. It can have the following components:
\begin{description}
\item[{\texttt{items}}] The list of attribute lines as described above.
\item[{\texttt{single}}] Boolean with the same meaning as the optional argument \mbox{\texttt{\mdseries\slshape single}}.
\item[{\texttt{none}}] Boolean with the same meaning as the optional argument \mbox{\texttt{\mdseries\slshape none}}.
\item[{\texttt{size}}] The size of the window like the first two arguments of \texttt{NCurses.newwin} (default is \texttt{[0, 0]}, as big as possible), or the string \texttt{"fit"} which means the smallest possible window.
\item[{\texttt{align}}] A substring of \texttt{"bclt"}, which describes the alignment of the window in the terminal. The meaning and
the default are the same as for \texttt{BrowseData.IsBrowseTableCellData} (\ref{BrowseData.IsBrowseTableCellData}).
\item[{\texttt{begin}}] Top-left corner of the window like the last two arguments of \texttt{NCurses.newwin} (default is \texttt{[0, 0]}, top-left of the screen). This value has priority over the \texttt{align} component.
\item[{\texttt{attribute}}] An attribute used for the display of the window (default is \texttt{NCurses.attrs.NORMAL}).
\item[{\texttt{border}}] If the window should be displayed with a border then set to \texttt{true} (default is \texttt{false}) or to an integer representing attributes such as the components of \texttt{NCurses.attrs} (see Section{\nobreakspace}\ref{ssec:ncursesAttrs}) or the return value of \texttt{NCurses.ColorAttr} (\ref{NCurses.ColorAttr}); these attributes are used for the border of the box. The default is \texttt{NCurses.attrs.NORMAL}.
\item[{\texttt{header}}] An attribute line used as header line (the default depends on the settings of \texttt{single} and \texttt{none}).
\item[{\texttt{hint}}] An attribute line used as hint in the last line of the window (the default
depends on the settings of \texttt{single} and \texttt{none}).
\item[{\texttt{onSubmitFunction}}] A function that is called when the user submits the selection; the argument
for this call is the current value of the record \mbox{\texttt{\mdseries\slshape poss}}. If the function returns \texttt{true} then the selected entries are returned as usual, otherwise the selection
window is kept open, waiting for new inputs; if the function returns a
nonempty list of attribute lines then these messages are shown using \texttt{NCurses.Alert} (\ref{NCurses.Alert}).
\end{description}
If mouse events are enabled (see \texttt{NCurses.UseMouse} (\ref{NCurses.UseMouse}))\index{mouse events} then the window can be moved on the screen via mouse events, the focus can be
moved to an entry, and (if \texttt{single} is \texttt{false}) the selection of an entry can be toggled.
\begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=Example]
!gapprompt@gap>| !gapinput@index := NCurses.Select(["Apples", "Pears", "Oranges"]);|
!gapprompt@gap>| !gapinput@index := NCurses.Select(rec(|
!gapprompt@>| !gapinput@ items := ["Apples", "Pears", "Oranges"],|
!gapprompt@>| !gapinput@ single := false,|
!gapprompt@>| !gapinput@ border := true,|
!gapprompt@>| !gapinput@ begin := [5, 5],|
!gapprompt@>| !gapinput@ size := [8, 60],|
!gapprompt@>| !gapinput@ header := "Choose at least two fruits",|
!gapprompt@>| !gapinput@ attribute := NCurses.ColorAttr("yellow","red"),|
!gapprompt@>| !gapinput@ onSubmitFunction:= function( r )|
!gapprompt@>| !gapinput@ if Length( r.RESULT ) < 2 then|
!gapprompt@>| !gapinput@ return [ "Choose at least two fruits" ];|
!gapprompt@>| !gapinput@ else|
!gapprompt@>| !gapinput@ return true;|
!gapprompt@>| !gapinput@ fi;|
!gapprompt@>| !gapinput@ end ) );|
\end{Verbatim}
}
\subsection{\textcolor{Chapter }{NCurses.GetLineFromUser}}
\logpage{[ 3, 1, 3 ]}\nobreak
\hyperdef{L}{X837EFD8A842257EA}{}
{\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{NCurses.GetLineFromUser({\mdseries\slshape pre})\index{NCurses.GetLineFromUser@\texttt{NCurses.GetLineFromUser}}
\label{NCurses.GetLineFromUser}
}\hfill{\scriptsize (function)}}\\
\textbf{\indent Returns:\ }
User input as string.
This function can be used to get an input string from the user. It opens a one
line window and writes the given string \mbox{\texttt{\mdseries\slshape pre}} into it. Then it waits for user input. After hitting the \textsc{Return} key the typed line is returned as a string to \textsf{GAP}. If the user exits via hitting the \textsc{Esc} key instead of hitting the \textsc{Return} key, the function returns \texttt{false}. (The \textsc{Esc} key may be recognized as input only after a delay of about a second.)
Some simple editing is possible during user input: The \textsc{Left}, \textsc{Right}, \textsc{Home} and \textsc{End} keys, the \textsc{Insert}/\textsc{Replace} keys, and the \textsc{Backspace}/\textsc{Delete} keys are supported.
Instead of a string, \mbox{\texttt{\mdseries\slshape pre}} can also be a record with the component \texttt{prefix}, whose value is the string described above. The following optional components
of this record are supported.
\begin{description}
\item[{\texttt{window}}] The window with the input field is created relative to this window, the
default is $0$.
\item[{\texttt{begin}}] This is a list with the coordinates of the upper left corner of the window
with the input field, relative to the window described by the \texttt{window} component; the default is \texttt{[ y-4, 2 ]}, where \texttt{y} is the height of this window.
\item[{\texttt{default}}] This string appears as result when the window is opened, the default is an
empty string.
\end{description}
\begin{Verbatim}[commandchars=@|A,fontsize=\small,frame=single,label=Example]
@gapprompt|gap>A @gapinput|str := NCurses.GetLineFromUser("Your Name: ");;A
@gapprompt|gap>A @gapinput|Print("Hello ", str, "!\n");A
\end{Verbatim}
}
\subsection{\textcolor{Chapter }{NCurses.Pager}}
\logpage{[ 3, 1, 4 ]}\nobreak
\hyperdef{L}{X87E1B2787F588CC0}{}
{\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{NCurses.Pager({\mdseries\slshape lines[, border[, ly, lx, y, x]]})\index{NCurses.Pager@\texttt{NCurses.Pager}}
\label{NCurses.Pager}
}\hfill{\scriptsize (function)}}\\
This is a simple pager utility for displaying and scrolling text. The argument \mbox{\texttt{\mdseries\slshape lines}} can be a list of attribute lines (see \texttt{NCurses.IsAttributeLine} (\ref{NCurses.IsAttributeLine})) or a string (the lines are separated by newline characters) or a record. In
case of a record the following components are recognized:
\begin{description}
\item[{\texttt{lines}}] The list of attribute lines or a string as described above.
\item[{\texttt{start}}] Line number to start the display.
\item[{\texttt{size}}] The size \texttt{[ly, lx]} of the window like the first two arguments of \texttt{NCurses.newwin} (default is \texttt{[0, 0]}, as big as possible).
\item[{\texttt{begin}}] Top-left corner \texttt{[y, x]} of the window like the last two arguments of \texttt{NCurses.newwin} (default is \texttt{[0, 0]}, top-left of the screen).
\item[{\texttt{attribute}}] An attribute used for the display of the window (default is \texttt{NCurses.attrs.NORMAL}).
\item[{\texttt{border}}] Either one of \texttt{true}/\texttt{false} to show the pager window with or without a standard border. Or it can be
string with eight, two or one characters, giving characters to be used for a
border, see \texttt{NCurses.WBorder} (\ref{NCurses.WBorder}).
\item[{\texttt{hint}}] A text for usage info in the last line of the window.
\end{description}
As an abbreviation the information from \texttt{border}, \texttt{size} and \texttt{begin} can also be specified in optional arguments.
\begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=Example]
!gapprompt@gap>| !gapinput@lines := List([1..100],i-> ["line ",NCurses.attrs.BOLD,String(i)]);;|
!gapprompt@gap>| !gapinput@NCurses.Pager(lines);|
\end{Verbatim}
}
\subsection{\textcolor{Chapter }{Selection of help matches}}\label{ssec:selhelpmatch}
\logpage{[ 3, 1, 5 ]}
\hyperdef{L}{X7D5685767D4FCD8E}{}
{
After loading the \textsf{Browse} package \textsf{GAP}'s help system behaves slightly different when a request yields several
matches. The matches are shown via \texttt{NCurses.Select} (\ref{NCurses.Select}), the list can be searched and filtered, and one can choose one match for
immediate display. It is possible to not choose a match and the \texttt{?{\textless}nr{\textgreater}} syntax still works.
If you want the original behavior call \texttt{SetUserPreference( "Browse", "SelectHelpMatches", false );} in your \textsf{GAP} session or \texttt{gap.ini} file, see{\nobreakspace} (\textbf{Reference: Configuring User preferences}). }
\subsection{\textcolor{Chapter }{Selection of package names}}\label{ssec:selpackagename}
\logpage{[ 3, 1, 6 ]}
\hyperdef{L}{X867BB82985D7953A}{}
{
The function \texttt{LoadPackage} (\textbf{Reference: LoadPackage}) shows a list of matches if only a prefix of a package name is given. After
loading the \textsf{Browse} package, \texttt{NCurses.Select} (\ref{NCurses.Select}) is used for that, and one can choose a match.
If you want the original behavior call \texttt{SetUserPreference( "Browse", "SelectPackageName", false );} in your \textsf{GAP} session or \texttt{gap.ini} file, see{\nobreakspace} (\textbf{Reference: Configuring User preferences}). }
}
\section{\textcolor{Chapter }{A Demo Function}}\label{sec:demo}
\logpage{[ 3, 2, 0 ]}
\hyperdef{L}{X7EF34E0E7FBD3A3B}{}
{
\subsection{\textcolor{Chapter }{NCurses.Demo}}
\logpage{[ 3, 2, 1 ]}\nobreak
\hyperdef{L}{X8681359F8064597B}{}
{\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{NCurses.Demo({\mdseries\slshape [inputs]})\index{NCurses.Demo@\texttt{NCurses.Demo}}
\label{NCurses.Demo}
}\hfill{\scriptsize (function)}}\\
Let \mbox{\texttt{\mdseries\slshape inputs}} be a list of records, each with the components \texttt{title} (a string), \texttt{inputblocks} (a list of strings, each describing some \textsf{GAP} statements), and optionally \texttt{footer} (a string) and \texttt{cleanup} (a string describing \textsf{GAP} statements). The default is \texttt{NCurses.DemoDefaults}.
\texttt{NCurses.Demo} lets the user choose an entry from \mbox{\texttt{\mdseries\slshape inputs}}, via \texttt{NCurses.Select} (\ref{NCurses.Select}), and then executes the \textsf{GAP} statements in the first entry of the \texttt{inputblocks} list of this entry; these strings, together with the values of \texttt{title} and \texttt{footer}, are shown in a window, at the bottom of the screen. The effects of calls to
functions using \texttt{ncurses} are shown in the rest of the screen. After the execution of the statements
(which may require user input), the user can continue with the next entry of \texttt{inputblocks}, or return to the \texttt{inputs} selection (and thus cancel the current \texttt{inputs} entry), or return to the execution of the beginning of the current \texttt{inputs} entry. At the end of the current entry of \texttt{inputs}, the user returns to the \texttt{inputs} selection.
The \textsf{GAP} statements in the \texttt{cleanup} component, if available, are executed whenever the user does not continue;
this is needed for deleting panels and windows that are defined in the
statements of the current entry.
Note that the \textsf{GAP} statements are executed in the \emph{global} scope, that is, they have the same effect as if they would be entered at the \textsf{GAP} prompt. Initially, \texttt{NCurses.Demo} sets the value of \texttt{BrowseData.defaults.work.windowParameters} to the parameters that describe the part of the screen above the window that
shows the inputs; so applications of \texttt{NCurses.BrowseGeneric} (\ref{NCurses.BrowseGeneric}) use automatically the maximal part of the screen as their window. It is
recommended to use a screen with at least $80$ columns and at least $37$ rows. }
}
}
\chapter{\textcolor{Chapter }{Browsing Tables in \textsf{GAP} using \texttt{ncurses} {\textendash}The User Interface}}\label{chap:browse-user}
\logpage{[ 4, 0, 0 ]}
\hyperdef{L}{X877E60DE7F53FDEC}{}
{
As stated in Section{\nobreakspace}\ref{sec:intro}, one aim of the \textsf{Browse} package is to provide tools for the quite usual task to show a two-dimensional
array or certain rows and columns of it on a character screen in a formatted
way, to navigate in this array via key strokes (and mouse events), and to
search for strings, to sort the array by row or column values etc.
The idea is that one starts with an array of data, the \emph{main table}\index{main table of a browse table}. Optionally, labels for each row of the main table are given, which are also
arranged in an array (with perhaps several columns), the \emph{row labels table}\index{row labels of a browse table}; analogously, a \emph{column labels table}\index{column labels of a browse table} of labels for the columns of the main table may be given. The row labels are
shown to the left of the main table, the column labels are shown above the
main table. The space above the row labels and to the left of the column
labels can be used for a fourth table, the \emph{corner table}\index{corner table of a browse table}, with information about the labels or about the main table. Optionally, a \emph{header}\index{header of a browse table} and a \emph{footer}\index{footer of a browse table} may be shown above and below these four tables, respectively. Header and
footer are not separated into columns. So the shown window has the following
structure.
\begin{center}
\begin{tabular}{|c|c|}
\hline
\multicolumn{2}{|c|}{header} \\
\hline
corner & column labels \\
\hline
& \\
row & main \\
labels & table \\
& \\
\hline
\multicolumn{2}{|c|}{footer} \\
\hline
\end{tabular}
\end{center}
If not the whole tables fit into the window then only subranges of rows and
columns of the main table are shown, together with the corresponding row and
column labels. Also in this case, the row heights and column widths are
computed w.r.t. the whole table not w.r.t. the shown rows and columns. This
means that the shown row labels are unchanged if the range of shown columns is
changed, the shown column labels are unchanged if the range of shown rows is
changed, and the whole corner table is always shown.
The current chapter describes the user interface for \emph{standard applications} of this kind, i.{\nobreakspace}e., those applications for which one just has
to collect the data to be shown in a record {\textendash}which we call a \emph{browse table}{\textendash} without need for additional \textsf{GAP} programming.
Section{\nobreakspace}\ref{sec:features} gives an overview of the features available in standard browse table
applications, and Section{\nobreakspace}\ref{sec:browsebasicdata} describes the data structures used in browse tables. Finally,
Section{\nobreakspace}\ref{sec:browsegeneric} introduces the function \texttt{NCurses.BrowseGeneric} (\ref{NCurses.BrowseGeneric}), which is the generic function for showing browse table in visual mode.
For technical details needed to extend these applications and to build other
applications, see Chapter{\nobreakspace}\ref{chap:browse-prg}.
Examples of browse table applications are shown in Chapter{\nobreakspace}\ref{ch:appl}.
\section{\textcolor{Chapter }{Features Supported by the Function \texttt{NCurses.BrowseGeneric} }}\label{sec:features}
\logpage{[ 4, 1, 0 ]}
\hyperdef{L}{X869EDB308717F199}{}
{
Standard applications of the function \texttt{NCurses.BrowseGeneric} (\ref{NCurses.BrowseGeneric}) have the following functionality. Other applications may provide only a
subset, or add further functionality, see Chapters{\nobreakspace}\ref{chap:browse-prg} and{\nobreakspace}\ref{ch:appl}.
\begin{description}
\item[{Scrolling:\index{scrolling in a browse table}}] The subranges of shown rows and columns of the main table can be modified,
such that the focus area is moved to the left, to the right, up, or down;
depending on the context, the focus is moved by one character, by one table
cell or a part of it, by the window height/width (minus one character or minus
one table cell). If mouse events \index{mouse events} are enabled then cells can be selected also via mouse clicks.
\item[{Selecting:\index{selecting entries of a browse table}}] A cell, row, or column of the main table can be selected; then it is shown
highlighted on the screen (by default using the attribute \texttt{NCurses.attrs.STANDOUT}, see Section{\nobreakspace}\ref{ssec:ncursesAttrs}). The selection can be moved inside the main table to a neighboring cell,
row, or column; this causes also scrolling of the main table when the window
borders are reached.
\item[{Searching:\index{searching in a browse table}}] A search string is entered by the user, and the first matching cell becomes
selected; one can search further for the next matching cell. Global search
parameters define what matching means (case sensitive or not, search for
substrings or complete words) and what the first and the next matching cells
are (search in the whole table or just in the selected row or column, search
for whole words or prefixes or suffixes, search forwards or backwards).
\item[{Sorting:\index{sorting a browse table}}] If a row or column is selected then the main table can be sorted w.r.t. the
entries in this row or column. Global sort parameters describe for example
whether one wants to sort ascending or descending, or case sensitive or not.
If a categorized table is sorted by a column then the category rows are
removed and the current sorting and filtering by rows is reset before the
table is sorted by the given column. If a table is sorted by a column/row that
is already sorted by a column/row then this ordering is reset first.
Sorting can be undone globally, i.{\nobreakspace}e., one can return to the
unsorted table.
\item[{Sorting and Categorizing:\index{categorizing a browse table}}] If a column is selected then the main table can be sorted w.r.t. the entries
in this column, and additionally these entries are turned into \emph{category rows}, i.{\nobreakspace}e., additional rows are added to the main table, appearing
immediately above the table rows with a fixed value in the selected column,
and showing this column value. (There should be no danger to mix up this
notion of categories with the one introduced in{\nobreakspace} (\textbf{Reference: Categories}).) The category rows can be \emph{collapsed} \index{collapsed category row} (that is, the table rows that belong to this category row are not shown) or \emph{expanded}\index{expanded category row} (that is, the corresponding table rows are shown). Some of the global search
parameters affect the category rows, for example, whether the category rows
shall involve a counter showing the number of corresponding data rows, or
whether a row of the browse table appears under different category rows.
Sorting and categorizing can be undone globally, i.{\nobreakspace}e., one can
return to the unsorted table without category rows.
\item[{Filtering:\index{filtering a browse table}}] The browse table can be restricted to those rows or columns in which a given
search string occurs. (Also entries in collapsed rows can match; they remain
collapsed then.) As a consequence, the category rows are restricted to those
under which a matching row occurs. (It is irrelevant whether the search string
occurs in category rows.)
If the search string does not occur at all then a message is printed, and the
table remains as it was before. If a browse table is restricted then this fact
is indicated by the message ``restricted table'' in the lower right corner of the window.
When a column or row is selected then the search is restricted to the entries
in this column or row, respectively. Besides using a search, one can also
explicitly hide the selected row or column. Filtering in an already restricted
table restricts the shown rows or columns further.
Filtering can be undone globally, i.{\nobreakspace}e., one can return to the
unrestricted table.
\item[{Help:\index{help window for a browse table}}] Depending on the application and on the situation, different sets of user
inputs may be available and different meanings of these inputs are possible.
An overview of the currently available inputs and their meanings can be opened
in each situation, by hitting the \textsc{?} key.
\item[{Re-entering:}] When one has called \texttt{NCurses.BrowseGeneric} (\ref{NCurses.BrowseGeneric}) with a browse table, and returns from visual mode to the \textsf{GAP} prompt after some navigation steps, calling \texttt{NCurses.BrowseGeneric} again with this table will enter visual mode in the same situation where it
was left. For example, the cell in the top-left position will be the same as
before, and if a cell was selected before then this cell will be selected now.
(One can avoid this behavior using the optional second argument of \texttt{NCurses.BrowseGeneric}.)
\item[{Logging:\index{log of a browse table session}}] The integers corresponding to the user inputs in visual mode are collected in
a list that is stored in the component \texttt{dynamic.log} of the browse table. It can be used for repeating the inputs with the replay
feature. (For browse table applications that give the user no access to the
browse table itself, one can force the log to be assigned to the component \texttt{log} of the global variable \texttt{BrowseData}, \index{BrowseData.log} see Section{\nobreakspace}\ref{BrowseData}.)
\item[{Replay:\index{replay of a browse table session}}] Instead of interactively hitting keys in visual mode, one can prescribe the
user inputs to a browse table via a ``replay record''; the inputs are then processed with given time intervals. The easiest way to
create a meaningful replay record is via the function \texttt{BrowseData.SetReplay} (\ref{BrowseData.SetReplay}), with argument the \texttt{dynamic.log} component of the browse table in question that was stored in an interactive
session.
\end{description}
The following features are not available in standard applications. They
require additional programming.
\begin{description}
\item[{Clicking:\index{click on an entry of a browse table}}] One possible action is to ``click'' a selected cell, row, or column, by hitting the \textsc{Enter} key. It depends on the application what the effect is. A typical situation is
that a corresponding \textsf{GAP} object is added to the list of return values of \texttt{NCurses.BrowseGeneric} (\ref{NCurses.BrowseGeneric}). Again it depends on the application what this \textsf{GAP} object is. In order to use this feature, one has to provide a record whose
components are \textsf{GAP} functions, see Section{\nobreakspace}\ref{BrowseData} for details. If mouse events \index{mouse events} are enabled (see \texttt{NCurses.UseMouse} (\ref{NCurses.UseMouse})) then also mouse clicks can be used as an alternative to hitting the \textsc{Enter} key.
\item[{Return Value:\index{return value of a browse table session}}] The function \texttt{NCurses.BrowseGeneric} (\ref{NCurses.BrowseGeneric}) may have an application dependent return value. A typical situation is that a
list of objects corresponding to those cells is returned that were ``clicked'' in visual mode. In order to use this feature, one has to assign the desired
value to the component \texttt{dynamic.Return} of the browse table.
\end{description}
}
\section{\textcolor{Chapter }{Data Structures used by \texttt{NCurses.BrowseGeneric}}}\label{sec:browsebasicdata}
\logpage{[ 4, 2, 0 ]}
\hyperdef{L}{X82689212794DA877}{}
{
\subsection{\textcolor{Chapter }{BrowseData.IsBrowseTableCellData}}
\logpage{[ 4, 2, 1 ]}\nobreak
\hyperdef{L}{X82157A2684969A5F}{}
{\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{BrowseData.IsBrowseTableCellData({\mdseries\slshape obj})\index{BrowseData.IsBrowseTableCellData@\texttt{BrowseData.IsBrowseTableCellData}}
\label{BrowseData.IsBrowseTableCellData}
}\hfill{\scriptsize (function)}}\\
\textbf{\indent Returns:\ }
\texttt{true} if the argument is a list or a record in a supported format.
A \emph{table cell data object} describes the input data for the contents of a cell in a browse table. It is
represented by either an attribute line (see{\nobreakspace}\texttt{NCurses.IsAttributeLine} (\ref{NCurses.IsAttributeLine})), for cells of height one, or a list of attribute lines or a record with the
components \texttt{rows}, a list of attribute lines, and optionally \texttt{align}, a substring of \texttt{"bclt"}, which describes the alignment of the attribute lines in the table cell --
bottom, horizontally centered, left, and top alignment; the default is right
and vertically centered alignment. (Note that the height of a table row and
the width of a table column can be larger than the height and width of an
individual cell.)
\begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=Example]
!gapprompt@gap>| !gapinput@BrowseData.IsBrowseTableCellData( "abc" );|
true
!gapprompt@gap>| !gapinput@BrowseData.IsBrowseTableCellData( [ "abc", "def" ] );|
true
!gapprompt@gap>| !gapinput@BrowseData.IsBrowseTableCellData( rec( rows:= [ "ab", "cd" ],|
!gapprompt@>| !gapinput@ align:= "tl" ) );|
true
!gapprompt@gap>| !gapinput@BrowseData.IsBrowseTableCellData( "" );|
true
!gapprompt@gap>| !gapinput@BrowseData.IsBrowseTableCellData( [] );|
true
\end{Verbatim}
The \emph{empty string} is a table cell data object of height one and width zero whereas the \emph{empty list} (which is not in \texttt{IsStringRep} (\textbf{Reference: IsStringRep})) is a table cell data object of height zero and width zero. }
\subsection{\textcolor{Chapter }{BrowseData.BlockEntry}}
\logpage{[ 4, 2, 2 ]}\nobreak
\hyperdef{L}{X7CA598A77A70C3B3}{}
{\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{BrowseData.BlockEntry({\mdseries\slshape tablecelldata, height, width})\index{BrowseData.BlockEntry@\texttt{BrowseData.BlockEntry}}
\label{BrowseData.BlockEntry}
}\hfill{\scriptsize (function)}}\\
\textbf{\indent Returns:\ }
a list of attribute lines.
For a table cell data object \mbox{\texttt{\mdseries\slshape tablecelldata}} (see{\nobreakspace}\texttt{BrowseData.IsBrowseTableCellData} (\ref{BrowseData.IsBrowseTableCellData})) and two positive integers \mbox{\texttt{\mdseries\slshape height}} and \mbox{\texttt{\mdseries\slshape width}}, \texttt{BrowseData.BlockEntry} returns a list of \mbox{\texttt{\mdseries\slshape height}} attribute lines of displayed length \mbox{\texttt{\mdseries\slshape width}} each (see{\nobreakspace}\texttt{NCurses.WidthAttributeLine} (\ref{NCurses.WidthAttributeLine})), that represents the formatted version of \mbox{\texttt{\mdseries\slshape tablecelldata}}.
If the rows of \mbox{\texttt{\mdseries\slshape tablecelldata}} have different numbers of displayed characters then they are filled up to the
desired numbers of rows and columns, according to the alignment prescribed by \mbox{\texttt{\mdseries\slshape tablecelldata}}; the default alignment is right and vertically centered.
\begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=Example]
!gapprompt@gap>| !gapinput@BrowseData.BlockEntry( "abc", 3, 5 );|
[ " ", " abc", " " ]
!gapprompt@gap>| !gapinput@BrowseData.BlockEntry( rec( rows:= [ "ab", "cd" ],|
!gapprompt@>| !gapinput@ align:= "tl" ), 3, 5 );|
[ "ab ", "cd ", " " ]
\end{Verbatim}
}
\subsection{\textcolor{Chapter }{BrowseData.IsBrowseTable}}
\logpage{[ 4, 2, 3 ]}\nobreak
\hyperdef{L}{X81007E2F8552523B}{}
{\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{BrowseData.IsBrowseTable({\mdseries\slshape obj})\index{BrowseData.IsBrowseTable@\texttt{BrowseData.IsBrowseTable}}
\label{BrowseData.IsBrowseTable}
}\hfill{\scriptsize (function)}}\\
\textbf{\indent Returns:\ }
\texttt{true} if the argument record has the required components and is consistent.
A \emph{browse table} is a \textsf{GAP} record that can be used as the first argument of the function \texttt{NCurses.BrowseGeneric} (\ref{NCurses.BrowseGeneric}).
The supported components of a browse table are \texttt{work} and \texttt{dynamic}, their values must be records: The components in \texttt{work} describe that part of the data that are not likely to depend on user
interactions, such as the table entries and their heights and widths. The
components in \texttt{dynamic} describe that part of the data that is intended to change with user
interactions, such as the currently shown top-left entry of the table, or the
current status w.r.t. sorting. For example, suppose you call \texttt{NCurses.BrowseGeneric} (\ref{NCurses.BrowseGeneric}) twice with the same browse table; the second call enters the table in the same
status where it was left \emph{after} the first call if the component \texttt{dynamic} is kept, whereas one has to reset (which usually simply means to unbind) the
component \texttt{dynamic} if one wants to start in the same status as \emph{before} the first call.
The following components are the most important ones for standard browse
applications. All these components belong to the \texttt{work} record. For other supported components (of \texttt{work} as well as of \texttt{dynamic}) and for the meaning of the term ``mode'', see Section{\nobreakspace}\ref{sec:modes}.
\begin{description}
\item[{\texttt{main}}] is the list of lists of table cell data objects that form the matrix to be
shown. There is no default for this component. (It is possible to compute the
entries of the main table on demand, see the description of the component \texttt{Main} in Section{\nobreakspace}\ref{BrowseData}. In this situation, the value of the component \texttt{main} can be an empty list.)
\item[{\texttt{header}}] describes a header that shall be shown above the column labels. The value is
either a list of attribute lines (``static header'') or a function or a record whose component names are names of available modes
of the browse table (``dynamic header''). In the function case, the function must take the browse table as its only
argument, and return a list of attribute lines. In the record case, the values
of the components must be such functions. It is assumed that the number of
these lines depends at most on the mode. The default is an empty list,
i.{\nobreakspace}e., there is no header.
\item[{\texttt{footer}}] describes a footer that shall be shown below the table. The value is analogous
to that of \texttt{footer}. The default is an empty list, i.{\nobreakspace}e., there is no footer.
\item[{\texttt{labelsRow}}] is a list of row label rows, each being a list of table cell data objects.
These rows are shown to the left of the main table. The default is an empty
list, i.{\nobreakspace}e., there are no row labels.
\item[{\texttt{labelsCol}}] is a list of column information rows, each being a list of table cell data
objects. These rows are shown between the header and the main table. The
default is an empty list, i.{\nobreakspace}e., there are no column labels.
\item[{\texttt{corner}}] is a list of lists of table cell data objects that are printed in the upper
left corner, i.{\nobreakspace}e., to the left of the column label rows and
above the row label columns. The default is an empty list.
\item[{\texttt{sepRow}}] describes the separators above and below rows of the main table and of the row
labels table. The value is either an attribute line or a (not necessarily
dense) list of attribute lines. In the former case, repetitions of the
attribute line are used as separators below each row and above the first row
of the table; in the latter case, repetitions of the entry at the first
position (if bound) are used above the first row, and repetitions of the last
bound entry before the $(i+2)$-th position (if there is such an entry at all) are used below the $i$-th table row. The default is an empty string, which means that there are no
row separators.
\item[{\texttt{sepCol}}] describes the separators in front of and behind columns of the main table and
of the column labels table. The format of the value is analogous to that of
the component \texttt{sepRow}; the default is the string \texttt{" "} (whitespace of width one).
\item[{\texttt{sepLabelsCol}}] describes the separators above and below rows of the column labels table and
of the corner table, analogously to \texttt{sepRow}. The default is an empty string, which means that there are no column label
separators.
\item[{\texttt{sepLabelsRow}}] describes the separators in front of and behind columns of the row labels
table and of the corner table, analogously to \texttt{sepCol}. The default is an empty string.
\end{description}
We give a few examples of standard applications.
The first example defines a small browse table by prescribing only the
component \texttt{work.main}, so the defaults for row and column labels (no such labels), and for
separators are used. The table cells are given by plain strings, so they have
height one. Usually this table will fit on the screen.
\begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=Example]
!gapprompt@gap>| !gapinput@m:= 10;; n:= 5;;|
!gapprompt@gap>| !gapinput@xpl1:= rec( work:= rec(|
!gapprompt@>| !gapinput@ main:= List( [ 1 .. m ], i -> List( [ 1 .. n ],|
!gapprompt@>| !gapinput@ j -> String( [ i, j ] ) ) ) ) );;|
!gapprompt@gap>| !gapinput@BrowseData.IsBrowseTable( xpl1 );|
true
\end{Verbatim}
In the second example, also row and column labels appear, and different
separators are used. The table cells have height three. Also this table will
usually fit on the screen.
\begin{Verbatim}[commandchars=!@A,fontsize=\small,frame=single,label=Example]
!gapprompt@gap>A !gapinput@m:= 6;; n:= 5;;A
!gapprompt@gap>A !gapinput@xpl2:= rec( work:= rec(A
!gapprompt@>A !gapinput@ main:= List( [ 1 .. m ], i -> List( [ 1 .. n ],A
!gapprompt@>A !gapinput@ j -> rec( rows:= List( [ -i*j, i*j*1000+j, i-j ], String ),A
!gapprompt@>A !gapinput@ align:= "c" ) ) ),A
!gapprompt@>A !gapinput@ labelsRow:= List( [ 1 .. m ], i -> [ String( i ) ] ),A
!gapprompt@>A !gapinput@ labelsCol:= [ List( [ 1 .. n ], String ) ],A
!gapprompt@>A !gapinput@ sepRow:= "-",A
!gapprompt@>A !gapinput@ sepCol:= "|",A
!gapprompt@>A !gapinput@ ) );;A
!gapprompt@gap>A !gapinput@BrowseData.IsBrowseTable( xpl2 );A
true
\end{Verbatim}
The third example additionally has a static header and a dynamic footer, and
the table cells involve attributes. This table will usually not fit on the
screen. Note that \texttt{NCurses.attrs.ColorPairs} is available only if the terminal supports colors, which can be checked using \texttt{NCurses.attrs.has{\textunderscore}colors} (\ref{NCurses.attrs.hasuScorecolors}).
\begin{Verbatim}[commandchars=!@F,fontsize=\small,frame=single,label=Example]
!gapprompt@gap>F !gapinput@m:= 30;; n:= 25;;F
!gapprompt@gap>F !gapinput@xpl3:= rec( work:= rec(F
!gapprompt@>F !gapinput@ header:= [ " Example 3" ],F
!gapprompt@>F !gapinput@ labelsRow:= List( [ 1 .. 30 ], i -> [ String( i ) ] ),F
!gapprompt@>F !gapinput@ sepLabelsRow:= " % ",F
!gapprompt@>F !gapinput@ sepLabelsCol:= "=",F
!gapprompt@>F !gapinput@ sepRow:= "*",F
!gapprompt@>F !gapinput@ sepCol:= " |",F
!gapprompt@>F !gapinput@ footer:= t -> [ Concatenation( "top-left entry is: ",F
!gapprompt@>F !gapinput@ String( t.dynamic.topleft{ [ 1, 2] } ) ) ],F
!gapprompt@>F !gapinput@ ) );;F
!gapprompt@gap>F !gapinput@if NCurses.attrs.has_colors thenF
!gapprompt@>F !gapinput@ xpl3.work.main:= List( [ 1 .. m ], i -> List( [ 1 .. n ],F
!gapprompt@>F !gapinput@ j -> rec( rows:= [ String( -i*j ),F
!gapprompt@>F !gapinput@ [ NCurses.attrs.BOLD, true,F
!gapprompt@>F !gapinput@ NCurses.attrs.ColorPairs[56+1], true,F
!gapprompt@>F !gapinput@ String( i*j*1000+j ),F
!gapprompt@>F !gapinput@ NCurses.attrs.NORMAL, true ],F
!gapprompt@>F !gapinput@ String( i-j ) ],F
!gapprompt@>F !gapinput@ align:= "c" ) ) );F
!gapprompt@>F !gapinput@ xpl3.work.labelsCol:= [ List( [ 1 .. 30 ], i -> [F
!gapprompt@>F !gapinput@ NCurses.attrs.ColorPairs[ 56+4 ], true,F
!gapprompt@>F !gapinput@ String( i ),F
!gapprompt@>F !gapinput@ NCurses.attrs.NORMAL, true ] ) ];F
!gapprompt@>F !gapinput@elseF
!gapprompt@>F !gapinput@ xpl3.work.main:= List( [ 1 .. m ], i -> List( [ 1 .. n ],F
!gapprompt@>F !gapinput@ j -> rec( rows:= [ String( -i*j ),F
!gapprompt@>F !gapinput@ [ NCurses.attrs.BOLD, true,F
!gapprompt@>F !gapinput@ String( i*j*1000+j ),F
!gapprompt@>F !gapinput@ NCurses.attrs.NORMAL, true ],F
!gapprompt@>F !gapinput@ String( i-j ) ],F
!gapprompt@>F !gapinput@ align:= "c" ) ) );F
!gapprompt@>F !gapinput@ xpl3.work.labelsCol:= [ List( [ 1 .. 30 ], i -> [F
!gapprompt@>F !gapinput@ NCurses.attrs.BOLD, true,F
!gapprompt@>F !gapinput@ String( i ),F
!gapprompt@>F !gapinput@ NCurses.attrs.NORMAL, true ] ) ];F
!gapprompt@>F !gapinput@fi;F
!gapprompt@gap>F !gapinput@BrowseData.IsBrowseTable( xpl3 );F
true
\end{Verbatim}
The fourth example illustrates that highlighting may not work properly for
browse tables containing entries whose attributes are not set with explicit
Boolean values, see \texttt{NCurses.IsAttributeLine} (\ref{NCurses.IsAttributeLine}). Call \texttt{NCurses.BrowseGeneric} (\ref{NCurses.BrowseGeneric}) with the browse table \texttt{xpl4}, and select an entry (or a column or a row): Only the middle row of each
selected cell will be highlighted, because only in this row, the color
attribute is switched on with an explicit \texttt{true}.
\begin{Verbatim}[commandchars=@FG,fontsize=\small,frame=single,label=Example]
@gappromptFgap>G @gapinputFxpl4:= rec(G
@gappromptF>G @gapinputF defc:= NCurses.defaultColors,G
@gappromptF>G @gapinputF wd:= Maximum( List( ~.defc, Length ) ),G
@gappromptF>G @gapinputF ca:= NCurses.ColorAttr,G
@gappromptF>G @gapinputF work:= rec(G
@gappromptF>G @gapinputF header:= [ "Examples of NCurses.ColorAttr" ],G
@gappromptF>G @gapinputF main:= List( ~.defc, i -> List( ~.defc,G
@gappromptF>G @gapinputF j -> [ [ ~.ca( i, j ), String( i, ~.wd ) ], # no true!G
@gappromptF>G @gapinputF [ ~.ca( i, j ), true, String( "on", ~.wd ) ],G
@gappromptF>G @gapinputF [ ~.ca( i, j ), String( j, ~.wd ) ] ] ) ), # no true!G
@gappromptF>G @gapinputF labelsRow:= List( ~.defc, i -> [ String( i ) ] ),G
@gappromptF>G @gapinputF labelsCol:= [ List( ~.defc, String ) ],G
@gappromptF>G @gapinputF sepRow:= "-",G
@gappromptF>G @gapinputF sepCol:= [ " |", "|" ],G
@gappromptF>G @gapinputF ) );;G
@gappromptFgap>G @gapinputFBrowseData.IsBrowseTable( xpl4 );G
true
\end{Verbatim}
}
}
\section{\textcolor{Chapter }{The Function \texttt{NCurses.BrowseGeneric}}}\label{sec:browsegeneric}
\logpage{[ 4, 3, 0 ]}
\hyperdef{L}{X8135D3C2806D8F92}{}
{
\subsection{\textcolor{Chapter }{NCurses.BrowseGeneric}}
\logpage{[ 4, 3, 1 ]}\nobreak
\hyperdef{L}{X85FC163D87FAFD12}{}
{\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{NCurses.BrowseGeneric({\mdseries\slshape t[, arec]})\index{NCurses.BrowseGeneric@\texttt{NCurses.BrowseGeneric}}
\label{NCurses.BrowseGeneric}
}\hfill{\scriptsize (function)}}\\
\textbf{\indent Returns:\ }
an application dependent value, or nothing.
\texttt{NCurses.BrowseGeneric} is used to show the browse table \mbox{\texttt{\mdseries\slshape t}} (see{\nobreakspace}\texttt{BrowseData.IsBrowseTable} (\ref{BrowseData.IsBrowseTable})) in a formatted way on a text screen, and allows the user to navigate in this
table.
The optional argument \mbox{\texttt{\mdseries\slshape arec}}, if given, must be a record whose components \texttt{work} and \texttt{dynamic}, if bound, are used to provide defaults for missing values in the
corresponding components of \mbox{\texttt{\mdseries\slshape t}}. The default for \mbox{\texttt{\mdseries\slshape arec}} and for the components not provided in \mbox{\texttt{\mdseries\slshape arec}} is \texttt{BrowseData.defaults}, see{\nobreakspace}\texttt{BrowseData} (\ref{BrowseData}), the function \texttt{BrowseData.SetDefaults} sets these default values.
At least the component \texttt{work.main} must be bound in \mbox{\texttt{\mdseries\slshape t}}, with value a list of list of table cell data objects, see{\nobreakspace}\texttt{BrowseData.IsBrowseTableCellData} (\ref{BrowseData.IsBrowseTableCellData}).
When the window or the screen is too small for the browse table, according to
its component \texttt{work.minyx}, the table will not be shown in visual mode, and \texttt{fail} is returned. (This holds also if there would be no return value of the call in
a large enough screen.) Thus one should check for \texttt{fail} results of programmatic calls of \texttt{NCurses.BrowseGeneric}, and one should better not admit \texttt{fail} as a regular return value.
Most likely, \texttt{NCurses.BrowseGeneric} will not be called on the command line, but the browse table \mbox{\texttt{\mdseries\slshape t}} will be composed by a suitable function which then calls \texttt{NCurses.BrowseGeneric}, see the examples in Chapter{\nobreakspace}\ref{ch:appl}. }
}
}
\chapter{\textcolor{Chapter }{Browsing Tables in \textsf{GAP} using \texttt{ncurses} {\textendash}The Programming Interface}}\label{chap:browse-prg}
\logpage{[ 5, 0, 0 ]}
\hyperdef{L}{X82DDDC1783B4CA30}{}
{
This chapter describes some aspects of the internals of the browse table
handling. The relevant objects are \emph{action functions} that implement the individual navigation steps (see Section{\nobreakspace}\ref{sec:actions}), \emph{modes} that describe the sets of available navigation steps in given situations (see
Section{\nobreakspace}\ref{sec:modes}), and \emph{browse applications} that are given by the combination of several modes (see Section{\nobreakspace}\ref{sec:applications}). Most of the related data is stored in the global variable \texttt{BrowseData} (\ref{BrowseData}). For more details, one should look directly at the code in the file \texttt{lib/browse.gi} of the \textsf{Browse} package.
\section{\textcolor{Chapter }{Navigation Steps in Browse Tables}}\label{sec:actions}
\logpage{[ 5, 1, 0 ]}
\hyperdef{L}{X853E01C778A73ECB}{}
{
Navigating in a browse table means that after entering visual mode by calling \texttt{NCurses.BrowseGeneric} (\ref{NCurses.BrowseGeneric}), the user hits one or several keys, or uses a mouse button, and if this input
is in a given set of admissible inputs then a corresponding function is
executed with argument the browse table (plus additional information in the
case of mouse events). The function call then may change components in this
table (recommended: components in its \texttt{dynamic} component), such that the appearance in the window may be different
afterwards, and also the admissible inputs and their effects may have changed.
The relation between the admissible inputs and the corresponding functions is
application dependent. However, it is recommended to associate the same input
to the same function in different situations; for example, the \textsc{?} key and the \textsc{F1} key should belong to a function that shows a help window (see Section \ref{BrowseData.actions.ShowHelp}), the \textsc{q} key and the \textsc{Esc} key should belong to a function that exits the current mode (Note that the \textsc{Esc} key may be recognized as input only after a delay of about a second.), the \textsc{Q} key should belong to a function that exits the browse application (see Section \ref{BrowseData.actions.QuitMode}), the \textsc{F2} key should belong to a function that saves the current window contents in a
global variable (see Section \ref{BrowseData.actions.SaveWindow}), and the \textsc{E} key should belong to a function that enters a break loop (see
Section{\nobreakspace}\ref{BrowseData.actions.Error}). The \textsc{Enter} and \textsc{Return} keys should belong to a ``click'' on a selected table entry, and if a category row is selected then they should
expand/collapse this category. The \textsc{M} key should toggle enabling and disabling mouse events. Mouse events on a cell
or on a category row of a browse table should move the selected entry to this
position; it is recommended that no functionality is lost if no mouse events
are used, although the number of steps might be reduced when the mouse is
used.
Each such function is wrapped into a record with the components \texttt{action} (the function itself) and \texttt{helplines} (a list of attribute lines that describes what the function does). \index{action record of a browse table} The help lines are used by the help feature of \texttt{NCurses.BrowseGeneric}, see Section \ref{BrowseData.actions.ShowHelp}.
The action functions need not return anything. Whenever the shown screen shall
be recomputed after the function call, the component \texttt{dynamic.changed} of the browse table must be set to \texttt{true} by the action functions.
After entering the first characters of an admissible input that consists of
more characters, the last line of the window with the browse table shows these
characters behind the prefix ``partial input:''. \index{partial input in a browse table} One can delete the last entered character of a partial input via the \textsc{Delete} and \textsc{Backspace} keys. It is not possible to make these keys part of an admissible input. When
a partial input is given, only those user inputs have an effect that extend
the partial input to (a prefix of) an admissible input. For example, asking
for help by hitting the \textsc{?} key will in general not work if a partial input had been entered before. }
\section{\textcolor{Chapter }{Modes in Browse Tables}}\label{sec:modes}
\logpage{[ 5, 2, 0 ]}
\hyperdef{L}{X83290BB6864B2DD0}{}
{
\index{mode of a browse table} In different situations, different inputs may be admissible for the same
browse table, and different functions may belong to the same input. For
example, the meaning of ``moving down'' can be different depending on whether a cell is selected or not.
The set of admissible user inputs and corresponding functions for a particular
situation is collected in a \emph{mode} of the browse table. (There should be no danger to mix up this notion of mode
with the ``visual mode'' introduced in Section{\nobreakspace}\ref{sec:intro}.) A mode is represented by a record with the components \texttt{name} (a string used to associate the mode with the components of \texttt{header}, \texttt{headerLength}, \texttt{footer}, \texttt{footerLength}, \texttt{Click}, and for the help screen), \texttt{flag} (a string that describes properties of the mode but that can be equal for
different modes), \texttt{actions} (a list of records describing the navigation steps that are admissible in the
mode, see Section{\nobreakspace}\ref{sec:actions}), and \texttt{ShowTables} (the function used to eventually print the current window contents, the
default is \texttt{BrowseData.ShowTables}). \index{BrowseData.ShowTables} Due to the requirement that each admissible user input uniquely determines a
corresponding function, no admissible user input can be a prefix of another
admissible input, for the same mode.
Navigation steps (see Section \ref{sec:actions}) can change the current mode or keep the mode. It is recommended that each
mode has an action to leave this mode; also an action to leave the browse
table application is advisable.
In a browse table, all available modes are stored in the component \texttt{work.availableModes}, whose value is a list of mode records. The value of the component \texttt{dynamic.activeModes} is a list of mode records that is used as a stack: The \emph{current mode} is the last entry in this list, changing the current mode is achieved by
unbinding the last entry (so one returns to the mode from which the current
mode had been entered by adding it to the list), by adding a new mode record
(so one can later return to the current mode), or by replacing the last entry
by another mode record. As soon as the \texttt{dynamic.activeModes} list becomes empty, the browse table application is left. (In this situation,
if the browse table had been entered from the \textsf{GAP} prompt then visual mode is left, and one returns to the \textsf{GAP} prompt.)
The following modes are predefined by the \textsf{Browse} package. Each of these modes admits the user inputs \textsc{?}, \textsc{F1}, \textsc{q}, \textsc{Esc}, \textsc{Q}, \textsc{F2}, \textsc{E}, and \textsc{M} that have been mentioned in Section \ref{sec:actions}.
\begin{description}
\item[{browse}] This mode admits scrolling of the browse table by a cell or by a screen,
searching for a string, selecting a row, a column, or an entry, and expanding
or collapsing all category rows.
\item[{help}] This mode is entered by calling \texttt{BrowseData.ShowHelpTable}; it shows a help window concerning the actions available in the mode from
which the \texttt{help} mode was entered. The \texttt{help} mode admits scrolling in the help table by a cell or by a screen. See Section \ref{BrowseData.actions.ShowHelp} for details.
\item[{select{\textunderscore}entry}] In this mode, one table cell is regarded as selected; this cell is highlighted
using the attribute in the component \texttt{work.startSelect} as a prefix of each attribute line, see the remark in Section \ref{NCurses.IsAttributeLine}. The mode admits moving the selection by one cell in the four directions,
searching for a string and for further occurrences of this string, expanding
or collapsing the current category row or all category rows, and executing the ``click'' function of this mode, provided that the component \texttt{work.Click.( "select{\textunderscore}entry" )} of the browse table is bound.
\item[{select{\textunderscore}row}] This is like the \texttt{select{\textunderscore}entry} mode, except that a whole row of the browse table is highlighted. Searching is
restricted to the selected row, and ``click'' refers to the function \texttt{work.Click.( "select{\textunderscore}row" )}.
\item[{select{\textunderscore}row{\textunderscore}and{\textunderscore}entry}] This is a combination of the \texttt{select{\textunderscore}entry} mode and the \texttt{select{\textunderscore}row} mode.
\item[{select{\textunderscore}column}] This is like the \texttt{select{\textunderscore}row} mode, just a column is selected not a row.
\item[{select{\textunderscore}column{\textunderscore}and{\textunderscore}entry}] This is like the \texttt{select{\textunderscore}row{\textunderscore}and{\textunderscore}entry} mode, just a column is selected not a row.
\end{description}
}
\section{\textcolor{Chapter }{Browse Applications}}\label{sec:applications}
\logpage{[ 5, 3, 0 ]}
\hyperdef{L}{X7A4014DB84D16406}{}
{
The data in a browse table together with the set of its available modes and
the stack of active modes forms a browse application. So the part of or all
functionality of the \textsf{Browse} package can be available (``standard application''), or additional functionality can be provided by extending available modes or
adding new modes.
When \texttt{NCurses.BrowseGeneric} (\ref{NCurses.BrowseGeneric}) has been called with the browse table \mbox{\texttt{\mdseries\slshape t}}, say, the following loop is executed.
\begin{enumerate}
\item If the list \mbox{\texttt{\mdseries\slshape t}}\texttt{.dynamic.activeModes} is empty then exit the browse table, and if the component \mbox{\texttt{\mdseries\slshape t}}\texttt{.dynamic.Return} is bound then return its value. Otherwise proceed with step 2.
\item If \mbox{\texttt{\mdseries\slshape t}}\texttt{.dynamic.changed} is \texttt{true} then call the \texttt{ShowTables} function of the current mode; this causes a redraw of the window that shows
the browse table. Then go to step 3.
\item Get one character of user input. If then the current user input string is the
name of an action of the current mode then call the corresponding action
function and go to step 1; if the current user input string is just a prefix
of the name of some actions of the current mode then go to step 3; if the
current user input string is not a prefix of any name of an action of the
current mode then discard the last read character and go to step 3.
\end{enumerate}
When one designs a new application, it may be not obvious whether some
functionality shall be implemented via one mode or via several modes. As a
rule of thumb, introducing a new mode is recommended when one needs a new set
of admissible actions in a given situation, and also if one wants to allow the
user to perform some actions and then to return to the previous status. }
\section{\textcolor{Chapter }{Predefined Browse Functionalities}}\label{sec:browse-avail}
\logpage{[ 5, 4, 0 ]}
\hyperdef{L}{X831DD0D58052AD57}{}
{
\subsection{\textcolor{Chapter }{BrowseData}}
\logpage{[ 5, 4, 1 ]}\nobreak
\hyperdef{L}{X86E80E578085F137}{}
{\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{BrowseData\index{BrowseData@\texttt{BrowseData}}
\label{BrowseData}
}\hfill{\scriptsize (global variable)}}\\
This is the record that contains the global data used by the function \texttt{NCurses.BrowseGeneric} (\ref{NCurses.BrowseGeneric}). The components are \texttt{actions}, \texttt{defaults}, and several capitalized names for which the values are functions.
\texttt{BrowseData.actions} is a record containing the action records that are provided by the package,
see Section{\nobreakspace}\ref{sec:actions}. These actions are used in standard applications of \texttt{NCurses.BrowseGeneric} (\ref{NCurses.BrowseGeneric}). Of course there is no problem with using actions that are not stored in \texttt{BrowseData.actions}.
\texttt{BrowseData.defaults} is a record that contains the defaults for the browse table used as the first
argument of \texttt{NCurses.BrowseGeneric} (\ref{NCurses.BrowseGeneric}). Important components have been described above, see{\nobreakspace}\texttt{BrowseData.IsBrowseTable} (\ref{BrowseData.IsBrowseTable}), in the sense that these components provide default values of \texttt{work} components in browse tables. Here is a list of further interesting components.
The following components are provided in \texttt{BrowseData.defaults.work}.
\begin{description}
\item[{\texttt{windowParameters}}] is a list of four nonnegative integers, denoting the arguments of \texttt{NCurses.newwin} for the window in which the browse table shall be shown. The default is \texttt{[ 0, 0, 0, 0 ]}, i.{\nobreakspace}e., the window for the browse table is the full screen.
\item[{\texttt{minyx}}] is a list of length two, the entries must be either nonnegative integers,
denoting the minimal number of rows and columns that are required by the
browse table, or unary functions that return these values when they are
applied to the browse table; this is interesting for applications that do not
support scrolling, or for applications that may have large row or column
labels tables. The default is a list with two functions, the return value of
the first function is the sum of the heights of the table header, the column
labels table, the first table row, and the table footer, and the return value
of the second function is the sum of widths of the row labels table and the
width of the first column. (If the header/footer is given by a function then
this part of the table is ignored in the \texttt{minyx} default.) Note that the conditions are checked only when \texttt{NCurses.BrowseGeneric} (\ref{NCurses.BrowseGeneric}) is called, not after later changes of the screen size in a running browse
table application.
\item[{\texttt{align}}] is a substring of \texttt{"bclt"}, which describes the alignment of the browse table in the window. The meaning
and the default are the same as for \texttt{BrowseData.IsBrowseTableCellData} (\ref{BrowseData.IsBrowseTableCellData}). (Of course this is relevant only if the table is smaller than the window.)
\item[{\texttt{headerLength}}] describes the lengths of the headers in the modes for which \texttt{header} functions are provided. The value is a record whose component names are names
of modes and the corresponding components are nonnegative integers. This
component is ignored if the \texttt{header} component is unbound or bound to a list, missing values are computed by calls
to the corresponding \texttt{header} function as soon as they are needed.
\item[{\texttt{footerLength}}] corresponds to \texttt{footer} in the same way as \texttt{headerLength} to \texttt{header}.
\item[{\texttt{Main}}] if bound to a function then this function can be used to compute missing
values for the component \texttt{main}; this way one can avoid computing/storing all \texttt{main} values at the same time. The access to the entries of the main matrix is
defined as follows: If \texttt{mainFormatted[i][j]} is bound then take it, if \texttt{main[i][j]} is bound then take it and compute the formatted version, if \texttt{Main} is a function then call it with arguments the browse table, \texttt{i}, and \texttt{j}, and compute the formatted version, otherwise compute the formatted version
of \texttt{work.emptyCell}. (For the condition whether entries in \texttt{mainFormatted} can be bound, see below in the description of the component \texttt{cacheEntries}.)
\item[{\texttt{cacheEntries}}] describes whether formatted values of the entries in the matrices given by the
components \texttt{corner}, \texttt{labelsCol}, \texttt{labelsRow}, \texttt{main}, and of the corresponding row and column separators shall be stored in the
components \texttt{cornerFormatted}, \texttt{labelsColFormatted}, \texttt{labelsRowFormatted}, and \texttt{mainFormatted}. The value must be a Boolean, the default is \texttt{false}; it should be set to \texttt{true} only if the tables are reasonably small.
\item[{\texttt{cornerFormatted}}] is a list of lists of formatted entries corresponding to the \texttt{corner} component. Each entry is either an attribute line or a list of attribute lines
(with the same number of displayed characters), the values can be computed
from the input format with \texttt{BrowseData.FormattedEntry}. \index{BrowseData.FormattedEntry@\texttt{BrowseData.FormattedEntry}} The entries are stored in this component only if the component \texttt{cacheEntries} has the value \texttt{true}. The default is an empty list.
\item[{\texttt{labelsColFormatted}}] corresponds to \texttt{labelsCol} in the same way as \texttt{cornerFormatted} to \texttt{corner}.
\item[{\texttt{labelsRowFormatted}}] corresponds to \texttt{labelsRow} in the same way as \texttt{cornerFormatted} to \texttt{corner}.
\item[{\texttt{mainFormatted}}] corresponds to \texttt{main} in the same way as \texttt{cornerFormatted} to \texttt{corner}.
\item[{\texttt{m0}}] is the maximal number of rows in the column labels table. If this value is not
bound then it is computed from the components \texttt{corner} and \texttt{labelsCol}.
\item[{\texttt{n0}}] is the maximal number of columns in \texttt{corner} and \texttt{labelsRow}.
\item[{\texttt{m}}] is the maximal number of rows in \texttt{labelsRow} and \texttt{main}. This value \emph{must} be set in advance if the values of \texttt{main} are computed using a \texttt{Main} function, and if the number of rows in \texttt{main} is larger than that in \texttt{labelsRow}.
\item[{\texttt{n}}] is the maximal number of columns in \texttt{labelsCol} and \texttt{main}. This value \emph{must} be set in advance if the values of \texttt{main} are computed using a \texttt{Main} function, and if the number of columns in \texttt{main} is larger than that in \texttt{labelsCol}.
\item[{\texttt{heightLabelsCol}}] is a list of $2$ \texttt{m0}$ + 1$ nonnegative integers, the entry at position $i$ is the maximal height of the entries in the $i$-th row of \texttt{cornerFormatted} and \texttt{labelsColFormatted}. Values that are not bound are computed on demand from the table entries,
with the function \texttt{BrowseData.HeightLabelsCol}. \index{BrowseData.HeightLabelsCol@\texttt{BrowseData.HeightLabelsCol}} (So if one knows the needed heights in advance, it is advisable to set the
values, in order to avoid that formatted table entries are computed just for
computing their size.) The default is an empty list.
\item[{\texttt{widthLabelsRow}}] is the corresponding list of $2$ \texttt{n0}$ + 1$ maximal widths of entries in \texttt{cornerFormatted} and \texttt{labelsRowFormatted}.
\item[{\texttt{heightRow}}] is the corresponding list of $2$ \texttt{m}$ + 1$ maximal heights of entries in \texttt{labelsRowFormatted} and \texttt{mainFormatted}.
\item[{\texttt{widthCol}}] is the corresponding list of $2$ \texttt{n}$ + 1$ maximal widths of entries in \texttt{labelsColFormatted} and \texttt{mainFormatted}.
\item[{\texttt{emptyCell}}] is a table cell data object to be used as the default for unbound positions in
the four matrices. The default is the empty list.
\item[{\texttt{sepCategories}}] is an attribute line to be used repeatedly as a separator below expanded
category rows. The default is the string \texttt{"-"}.
\item[{\texttt{startCollapsedCategory}}] is a list of attribute lines to be used as prefixes of unhidden but collapsed
category rows. For category rows of level $i$, the last bound entry before the $(i+1)$-th position is used. The default is a list of length one, the entry is the
boldface variant of the string \texttt{"{\textgreater} "}, so collapsed category rows on different levels are treated equally.
\item[{\texttt{startExpandedCategory}}] is a list of attribute lines to be used as prefixes of expanded category rows,
analogously to \texttt{startCollapsedCategory}. The default is a list of length one, the entry is the boldface variant of
the string \texttt{"* "}, so expanded category rows on different levels are treated equally.
\item[{\texttt{startSelect}}] is an attribute line to be used as a prefix of each attribute line that
belongs to a selected cell. The default is to switch the attribute \texttt{NCurses.attrs.STANDOUT} on, see Section{\nobreakspace}\ref{ssec:ncursesAttrs}.
\item[{\texttt{Click}}] is a record whose component names are names of available modes of the browse
table. The values are unary functions that take the browse table as their
argument. If the action \texttt{Click} is available in the current mode and the corresponding input is entered then
the function in the relevant component of the \texttt{Click} record is called.
\item[{\texttt{availableModes}}] is a list whose entries are the mode records that can be used when one
navigates through the browse table, see Section \ref{sec:modes}.
\item[{\texttt{SpecialGrid}}] is a function that takes a browse table and a record as its arguments. It is
called by \texttt{BrowseData.ShowTables} after the current contents of the window has been computed, and it is intended
to draw an individual grid into the table that fits better than anything that
can be specified in terms of row and column separators. (If other functions
than \texttt{BrowseData.ShowTables} are used in some modes of the browse table, these functions must deal with
this aspect themselves.) The default is to do nothing.
\end{description}
The following components are provided in \texttt{BrowseData.defaults.dynamic}.
\begin{description}
\item[{\texttt{changed}}] is a Boolean that must be set to \texttt{true} by action functions whenever a refresh of the window is necessary; it is
automatically reset to \texttt{false} after the refresh.
\item[{\texttt{indexRow}}] is a list of positive integers. The entry $k$ at position $i$ means that the $k$-th row in the \texttt{mainFormatted} table is shown as the $i$-th row. Note that depending on the current status of the browse table, the
rows of \texttt{mainFormatted} (and of \texttt{main}) may be permuted, or it may even happen that a row in \texttt{mainFormatted} is shown several times, for example under different category rows. It is
assumed (as a ``sort convention'') \index{sort convention} that the \emph{even} positions in \texttt{indexRow} point to \emph{even} numbers, and that the subsequent \emph{odd} positions (corresponding to the following separators) point to the subsequent \emph{odd} numbers. The default value is the list $[ 1, 2, \ldots, m ]$, where $m$ is the number of rows in \texttt{mainFormatted} (including the separator rows, so $m$ is always odd).
\item[{\texttt{indexCol}}] is the analogous list of positive integers that refers to columns.
\item[{\texttt{topleft}}] is a list of four positive integers denoting the current topleft position of
the main table. The value $[ i, j, k, l ]$ means that the topleft entry is indexed by the $i$-th entry in \texttt{indexRow}, the $j$-th entry in \texttt{indexCol}, and the $k$-th row and $l$-th column inside the corresponding cell. The default is $[ 1, 1, 1, 1 ]$.
\item[{\texttt{isCollapsedRow}}] is a list of Booleans, of the same length as the \texttt{indexRow} value. If the entry at position $i$ is \texttt{true} then the $i$-th row is currently not shown because it belongs to a collapsed category row.
It is assumed (as a ``hide convention'') \index{hide convention} that the value at any even position equals the value at the subsequent odd
position. The default is that all entries are \texttt{false}.
\item[{\texttt{isCollapsedCol}}] is the corresponding list for \texttt{indexCol}.
\item[{\texttt{isRejectedRow}}] is a list of Booleans. If the entry at position $i$ is \texttt{true} then the $i$-th row is currently not shown because it does not match the current filtering
of the table. Defaults, length, and hide convention are as for \texttt{isCollapsedRow}.
\item[{\texttt{isRejectedCol}}] is the corresponding list for \texttt{indexCol}.
\item[{\texttt{isRejectedLabelsRow}}] is a list of Booleans. If the entry at position $i$ is \texttt{true} then the $i$-th column of row labels is currently not shown.
\item[{\texttt{isRejectedLabelsCol}}] is the corresponding list for the column labels.
\item[{\texttt{activeModes}}] is a list of mode records that are contained in the \texttt{availableModes} list of the \texttt{work} component of the browse table. The current mode is the last entry in this
list. The default depends on the application, \texttt{BrowseData.defaults} prescribes the list containing only the mode with \texttt{name} component \texttt{"browse"}.
\item[{\texttt{selectedEntry}}] is a list $[ i, j ]$. If $i = j = 0$ then no table cell is selected, otherwise $i$ and $j$ are the row and column index of the selected cell. (Note that $i$ and $j$ are always even.) The default is $[ 0, 0 ]$.
\item[{\texttt{selectedCategory}}] is a list $[ i, l ]$. If $i = l = 0$ then no category row is selected, otherwise $i$ and $l$ are the row index and the level of the selected category row. (Note that $i$ is always even.) The default is $[ 0, 0 ]$.
\item[{\texttt{searchString}}] is the last string for which the user has searched in the table. The default
is the empty string.
\item[{\texttt{searchParameters}}] is a list of parameters that are modified by the function \texttt{BrowseData.SearchStringWithStartParameters}. \index{SearchStringWithStartParameters@\texttt{SearchStringWithStartParameters}} If one sets these parameters in a search then these values hold also for
subsequent searches. So it may make sense to set the parameters to personally
preferred ones.
\item[{\texttt{sortFunctionForColumnsDefault}}] is a function with two arguments used to compare two entries in the same
column of the main table (or two category row values). The default is the
operation \texttt{\texttt{\symbol{92}}{\textless}}. (Note that this default may be not meaningful if some of the rows or columns
contain strings representing numbers.)
\item[{\texttt{sortFunctionForRowsDefault}}] is the analogous function for comparing two entries in the same row of the
main table.
\item[{\texttt{sortFunctionsForRows}}] is a list of comparison functions, if the $i$-th entry is bound then it replaces the \texttt{sortFunctionForRowsDefault} value when the table is sorted w.r.t. the $i$-th row.
\item[{\texttt{sortFunctionsForColumns}}] is the analogous list of functions for the case that the table is sorted
w.r.t. columns.
\item[{\texttt{sortParametersForRowsDefault}}] is a list of parameters for sorting the main table w.r.t. entries in given
rows, e.{\nobreakspace}g., whether one wants to sort ascending or descending.
\item[{\texttt{sortParametersForColumnsDefault}}] is the analogous list of parameters for sorting w.r.t. given columns. In
addition to the parameters for rows, also parameters concerning category rows
are available, e.{\nobreakspace}g., whether the data columns that are
transformed into category rows shall be hidden afterwards or not.
\item[{\texttt{sortParametersForRows}}] is a list that contains ar position $i$, if bound, a list of parameters that shall replace those in \texttt{sortParametersForRowsDefault} when the table is sorted w.r.t. the $i$-th row.
\item[{\texttt{sortParametersForColumns}}] is the analogous list of parameters lists for sorting w.r.t. columns.
\item[{\texttt{categories}}] describes the current category rows. The value is a list $[ l_1, l_2, l_3 ]$ where $l_1$ is a \emph{sorted} list $[ i_1, i_2, ..., i_k ]$ of positive integers, $l_2$ is a list of length $k$ where the $j$-th entry is a record with the components \texttt{pos} (with value $i_j$), \texttt{level} (the level of the category row), \texttt{value} (an attribute line to be shown), \texttt{separator} (the separator below this category row is a repetition of this string), \texttt{isUnderCollapsedCategory} (\texttt{true} if the category row is hidden because a category row of an outer level is
collapsed; note that in the \texttt{false} case, the category row itself can be collapsed), \texttt{isRejectedCategory} (\texttt{true} if the category row is hidden because none of th edata rows below this
category match the current filtering of the table); the list $l_3$ contains the levels for which the category rows shall include the numbers of
data rows under these category rows. The default value is \texttt{[ [], [], [] ]}. (Note that this ``hide convention''\index{hide convention} makes sense mainly if together with a hidden category row, also the category
rows on higher levels and the corresponding data rows are hidden
{\textendash}but this property is \emph{not} checked.) Category rows are computed with the \texttt{CategoryValues} function in the \texttt{work} component of the browse table.
\item[{\texttt{log}}] describes the session log which is currently written. The value is a list of
positive integers, representing the user inputs in the current session. When \textsf{GAP} returns from a call to \texttt{NCurses.BrowseGeneric} (\ref{NCurses.BrowseGeneric}), one can access the log list of the user interactions in the browse table as
the value of its component \texttt{dynamic.log}.
If \texttt{BrowseData.logStore} \index{BrowseData.logStore@\texttt{BrowseData.logStore}} had been set to \texttt{true} before \texttt{NCurses.BrowseGeneric} (\ref{NCurses.BrowseGeneric}) had been called then the list can also be accessed as the value of \texttt{BrowseData.log}. \index{BrowseData.log@\texttt{BrowseData.log}} If \texttt{BrowseData.logStore} is unbound or has a value different from \texttt{true} then \texttt{BrowseData.log} is not written. (This can be interesting in the case of browse table
applications where the user does not get access to the browse table itself.)
\item[{\texttt{replay}}] describes the non-interactive input for the current browse table. The value is
a record with the components \texttt{logs} (a dense list of records, the default is an empty list) and \texttt{pointer} (a positive integer, the default is $1$). If \texttt{pointer} is a position in \texttt{logs} then currently the \texttt{pointer}-th record is processed, otherwise the browse table has exhausted its
non-interactive part, and requires interactive input. The records in \texttt{log} have the components \texttt{steps} (a list of user inputs, the default is an empty list), \texttt{position} (a positive integer denoting the current position in the \texttt{steps} list if the log is currently processed, the default is $1$), \texttt{replayInterval} (the timeout between two steps in milliseconds if the log is processed, the
default is $0$), and \texttt{quiet} (a Boolean, \texttt{true} if the steps shall not be shown on the screen until the end of the log is
reached, the default is \texttt{false}).
\end{description}
}
\subsection{\textcolor{Chapter }{BrowseData.SetReplay}}
\logpage{[ 5, 4, 2 ]}\nobreak
\hyperdef{L}{X791FB5BA7A9951F4}{}
{\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{BrowseData.SetReplay({\mdseries\slshape data})\index{BrowseData.SetReplay@\texttt{BrowseData.SetReplay}}
\label{BrowseData.SetReplay}
}\hfill{\scriptsize (function)}}\\
This function sets and resets the value of \texttt{BrowseData.defaults.dynamic.replay}.
When \texttt{BrowseData.SetReplay} is called with a list \mbox{\texttt{\mdseries\slshape data}} as its argument then the entries are assumed to describe user inputs for a
browse table for which \texttt{NCurses.BrowseGeneric} (\ref{NCurses.BrowseGeneric}) will be called afterwards, such that replay of the inputs runs. (Valid input
lists can be obtained from the component \texttt{dynamic.log} of the browse table in question.)
When \texttt{BrowseData.SetReplay} is called with the only argument \texttt{false}, the component is unbound (so replay is disabled, and thus calls to \texttt{NCurses.BrowseGeneric} (\ref{NCurses.BrowseGeneric}) will require interactive user input).
The replay feature should be used by initially setting the input list, then
running the replay (perhaps several times), and finally unbinding the inputs,
such that subsequent uses of other browse tables do not erroneously expect
their input in \texttt{BrowseData.defaults.dynamic.replay}.
Note that the value of \texttt{BrowseData.defaults.dynamic.replay} is used in a call to \texttt{NCurses.BrowseGeneric} (\ref{NCurses.BrowseGeneric}) only if the browse table in question does not have a component \texttt{dynamic.replay} before the call. }
\subsection{\textcolor{Chapter }{BrowseData.AlertWithReplay}}
\logpage{[ 5, 4, 3 ]}\nobreak
\hyperdef{L}{X7DAB32B785E59350}{}
{\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{BrowseData.AlertWithReplay({\mdseries\slshape t, messages[, attrs]})\index{BrowseData.AlertWithReplay@\texttt{BrowseData.AlertWithReplay}}
\label{BrowseData.AlertWithReplay}
}\hfill{\scriptsize (function)}}\\
\textbf{\indent Returns:\ }
an integer representing a (simulated) user input.
The function \texttt{BrowseData.AlertWithReplay} is a variant of \texttt{NCurses.Alert} (\ref{NCurses.Alert}) that is adapted for the replay feature of the browse table \mbox{\texttt{\mdseries\slshape t}}, see Section \ref{sec:features}. The arguments \mbox{\texttt{\mdseries\slshape messages}} and \mbox{\texttt{\mdseries\slshape attrs}} are the same as the corresponding arguments of \texttt{NCurses.Alert} (\ref{NCurses.Alert}), the argument \texttt{timeout} of \texttt{NCurses.Alert} (\ref{NCurses.Alert}) is taken from the browse table \mbox{\texttt{\mdseries\slshape t}}, as follows. If \texttt{BrowseData.IsDoneReplay} \index{BrowseData.IsDoneReplay@\texttt{BrowseData.IsDoneReplay}} returns \texttt{true} for \texttt{t} then \texttt{timeout} is zero, so a user input is requested for closing the alert box; otherwise the
requested input character is fetched from \texttt{t.dynamic.replay}.
If \texttt{timeout} is zero and mouse events are enabled (see \texttt{NCurses.UseMouse} (\ref{NCurses.UseMouse}))\index{mouse events} then the box can be moved inside the window via mouse events.
No alert box is shown if \texttt{BrowseData.IsQuietSession} \index{BrowseData.IsQuietSession@\texttt{BrowseData.IsQuietSession}} returns \texttt{true} when called with \mbox{\texttt{\mdseries\slshape t}}\texttt{.dynamic.replay}, otherwise the alert box is closed after the time (in milliseconds) that is
given by the \texttt{replayInterval} value of the current entry in \mbox{\texttt{\mdseries\slshape t}}\texttt{.dynamic.replay.logs}.
The function returns either the return value of the call to \texttt{NCurses.Alert} (\ref{NCurses.Alert}) (in the interactive case) or the value that was fetched from the current
replay record (in the replay case). }
\subsection{\textcolor{Chapter }{BrowseData.actions.ShowHelp}}
\logpage{[ 5, 4, 4 ]}\nobreak
\hyperdef{L}{X82A4238B79F06271}{}
{\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{BrowseData.actions.ShowHelp\index{BrowseData.actions.ShowHelp@\texttt{BrowseData.actions.ShowHelp}}
\label{BrowseData.actions.ShowHelp}
}\hfill{\scriptsize (global variable)}}\\
There are two predefined ways for showing an overview of the admissible inputs
and their meaning in the current mode of a browse table. The function \texttt{BrowseData.ShowHelpTable} \index{BrowseData.ShowHelpTable@\texttt{BrowseData.ShowHelpTable}} displays this overview in a browse table (using the \texttt{help} mode), and \texttt{BrowseData.ShowHelpPager} \index{BrowseData.ShowHelpPager@\texttt{BrowseData.ShowHelpPager}} uses \texttt{NCurses.Pager}.
Technically, the only difference between these two functions is that \texttt{BrowseData.ShowHelpTable} supports the replay feature of \texttt{NCurses.BrowseGeneric} (\ref{NCurses.BrowseGeneric}), whereas \texttt{BrowseData.ShowHelpPager} simply does not call the pager in replay situations.
The action record \texttt{BrowseData.actions.ShowHelp} is associated with the user inputs \textsc{?} or \textsc{F1} in standard \texttt{NCurses.BrowseGeneric} (\ref{NCurses.BrowseGeneric}) applications, and it is recommended to do the same in other \texttt{NCurses.BrowseGeneric} (\ref{NCurses.BrowseGeneric}) applications. This action calls the function stored in the component \texttt{work.ShowHelp} of the browse table, the default (i.{\nobreakspace}e., the value of \texttt{BrowseData.defaults.work.ShowHelp}) is \texttt{BrowseData.ShowHelpTable}.
\begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=Example]
!gapprompt@gap>| !gapinput@xpl1.work.ShowHelp:= BrowseData.ShowHelpPager;;|
!gapprompt@gap>| !gapinput@BrowseData.SetReplay( "?Q" );|
!gapprompt@gap>| !gapinput@Unbind( xpl1.dynamic );|
!gapprompt@gap>| !gapinput@NCurses.BrowseGeneric( xpl1 );|
!gapprompt@gap>| !gapinput@xpl1.work.ShowHelp:= BrowseData.ShowHelpTable;;|
!gapprompt@gap>| !gapinput@BrowseData.SetReplay( "?dQQ" );|
!gapprompt@gap>| !gapinput@Unbind( xpl1.dynamic );|
!gapprompt@gap>| !gapinput@NCurses.BrowseGeneric( xpl1 );|
!gapprompt@gap>| !gapinput@BrowseData.SetReplay( false );|
!gapprompt@gap>| !gapinput@Unbind( xpl1.dynamic );|
\end{Verbatim}
}
\subsection{\textcolor{Chapter }{BrowseData.actions.SaveWindow}}
\logpage{[ 5, 4, 5 ]}\nobreak
\hyperdef{L}{X872AE7387885B0AD}{}
{\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{BrowseData.actions.SaveWindow\index{BrowseData.actions.SaveWindow@\texttt{BrowseData.actions.SaveWindow}}
\label{BrowseData.actions.SaveWindow}
}\hfill{\scriptsize (global variable)}}\\
The function \texttt{BrowseData.actions.SaveWindow.action} asks the user to enter the name of a global \textsf{GAP} variable, using \texttt{NCurses.GetLineFromUser} (\ref{NCurses.GetLineFromUser}). If this variable name is valid and if no value is bound to this variable yet
then the current contents of the window of the browse table that is given as
the argument is saved in this variable, using \texttt{NCurses.SaveWin} (\ref{NCurses.SaveWin}). }
\subsection{\textcolor{Chapter }{BrowseData.actions.QuitMode}}
\logpage{[ 5, 4, 6 ]}\nobreak
\hyperdef{L}{X860DA4007E23716E}{}
{\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{BrowseData.actions.QuitMode\index{BrowseData.actions.QuitMode@\texttt{BrowseData.actions.QuitMode}}
\label{BrowseData.actions.QuitMode}
}\hfill{\scriptsize (global variable)}}\\
\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{BrowseData.actions.QuitTable\index{BrowseData.actions.QuitTable@\texttt{BrowseData.actions.QuitTable}}
\label{BrowseData.actions.QuitTable}
}\hfill{\scriptsize (global variable)}}\\
The function \texttt{BrowseData.actions.QuitMode.action} unbinds the current mode in the browse table that is given as its argument
(see Section \ref{sec:modes}), so the browse table returns to the mode from which this mode had been
called. If the current mode is the only one, first the user is asked for
confirmation whether she really wants to quit the table; only if the \textsc{y} key is hit, the last mode is unbound.
The function \texttt{BrowseData.actions.QuitTable.action} unbinds all modes in the browse table that is given as its argument, without
asking for confirmation; the effect is to exit the browse application (see
Section \ref{sec:applications}). }
\subsection{\textcolor{Chapter }{BrowseData.actions.Error}}
\logpage{[ 5, 4, 7 ]}\nobreak
\hyperdef{L}{X8728E4B6856EAEC0}{}
{\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{BrowseData.actions.Error\index{BrowseData.actions.Error@\texttt{BrowseData.actions.Error}}
\label{BrowseData.actions.Error}
}\hfill{\scriptsize (global variable)}}\\
After \texttt{NCurses.BrowseGeneric} (\ref{NCurses.BrowseGeneric}) has been called, interrupting by hitting the \textsc{Ctrl-C} keys is not possible. It is recommended to provide the action \texttt{BrowseData.actions.Error} for each mode of a \texttt{NCurses.BrowseGeneric} (\ref{NCurses.BrowseGeneric}) application, which enters a break loop and admits returning to the
application. The recommended user input for this action is the \textsc{E} key. }
}
}
\chapter{\textcolor{Chapter }{Examples of Applications based on \texttt{NCurses.BrowseGeneric} }}\label{ch:appl}
\logpage{[ 6, 0, 0 ]}
\hyperdef{L}{X78D4F8EA79405AF9}{}
{
This chapter introduces the operation \texttt{Browse} (\ref{Browse}) and lists several examples how the function \texttt{NCurses.BrowseGeneric} (\ref{NCurses.BrowseGeneric}) can be utilized for rendering \textsf{GAP} related data or for playing games. Each section describes the relevant \textsf{GAP} functions and briefly sketches the technical aspects of the implementation;
more details can be found in the \textsf{GAP} files, in the \texttt{app} directory of the package.
Only Section \ref{sec:tomdisp} describes a standard application in the sense of the introduction to Chapter \ref{chap:browse-user}, perhaps except for a special function that is needed to compare table
entries. The other examples in this chapter require some of the programming
described in Chapter \ref{chap:browse-prg}.
The \textsf{GAP} examples in this chapter use the ``replay'' feature of \texttt{NCurses.BrowseGeneric} (\ref{NCurses.BrowseGeneric}), see Section \ref{sec:features}. This means that the \texttt{NCurses.BrowseGeneric} (\ref{NCurses.BrowseGeneric}) based function is called between two calls of \texttt{BrowseData.SetReplay} (\ref{BrowseData.SetReplay}). If you want to paste these examples into the \textsf{GAP} session with the mouse then do not paste the final \texttt{BrowseData.SetReplay} (\ref{BrowseData.SetReplay}) call, since \texttt{NCurses.BrowseGeneric} (\ref{NCurses.BrowseGeneric}) would regard the additional input as a user interrupt.
\section{\textcolor{Chapter }{The Operation \texttt{Browse}}}\label{sec:browseoper}
\logpage{[ 6, 1, 0 ]}
\hyperdef{L}{X813F90F7815AB5B3}{}
{
\subsection{\textcolor{Chapter }{Browse}}
\logpage{[ 6, 1, 1 ]}\nobreak
\hyperdef{L}{X7FDD696B7DD54A6E}{}
{\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{Browse({\mdseries\slshape obj[, arec]})\index{Browse@\texttt{Browse}}
\label{Browse}
}\hfill{\scriptsize (operation)}}\\
This operation displays the \textsf{GAP} object \mbox{\texttt{\mdseries\slshape obj}} in a nice, formatted way, similar to the operation \texttt{Display} (\textbf{Reference: Display}). The difference is that \texttt{Browse} is intended to use \texttt{ncurses} facilities.
Currently there are methods for matrices (see{\nobreakspace}\texttt{Browse} (\ref{Browse:for a list of lists})), for character tables (see{\nobreakspace}\texttt{Browse} (\ref{Browse:for character tables})) and for tables of marks (see{\nobreakspace}\texttt{Browse} (\ref{Browse:for tables of marks})). }
}
\section{\textcolor{Chapter }{Matrix Display}}\label{sec:matrixdisp}
\logpage{[ 6, 2, 0 ]}
\hyperdef{L}{X7F6EE19480D10E2B}{}
{
The \textsf{GAP} library provides several \texttt{Display} (\textbf{Reference: Display}) methods for matrices. In order to cover the functionality of these methods, \textsf{Browse} provides the function \texttt{NCurses.BrowseDenseList} (\ref{NCurses.BrowseDenseList}) that uses the standard facilities of the function \texttt{NCurses.BrowseGeneric} (\ref{NCurses.BrowseGeneric}), i.{\nobreakspace}e., one can scroll in the matrix, searching and sorting are
provided etc.
The idea is to customize this function for different special cases, and to
install corresponding \texttt{Browse} (\ref{Browse}) methods. Examples are methods for matrices over finite fields and residue
class rings of the rational integers, see \texttt{Browse} (\ref{Browse:for a list of lists}).
The code can be found in the file \texttt{app/matdisp.g} of the package.
\subsection{\textcolor{Chapter }{NCurses.BrowseDenseList}}
\logpage{[ 6, 2, 1 ]}\nobreak
\hyperdef{L}{X8295F85D87118C83}{}
{\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{NCurses.BrowseDenseList({\mdseries\slshape list, arec})\index{NCurses.BrowseDenseList@\texttt{NCurses.BrowseDenseList}}
\label{NCurses.BrowseDenseList}
}\hfill{\scriptsize (function)}}\\
\textbf{\indent Returns:\ }
nothing.
Let \mbox{\texttt{\mdseries\slshape list}} be a dense list whose entries are lists, for example a matrix, and let \mbox{\texttt{\mdseries\slshape arec}} be a record. This function displays \mbox{\texttt{\mdseries\slshape list}} in a window, as a two-dimensional array with row and column positions as row
and column labels, respectively.
The following components of \mbox{\texttt{\mdseries\slshape arec}} are supported.
\begin{description}
\item[{\texttt{header}}] If bound, the value must be a valid value of the \texttt{work.header} component of a browse table, see \texttt{BrowseData.IsBrowseTable} (\ref{BrowseData.IsBrowseTable}); for example, the value can be a list of strings. If this component is not
bound then the browse table has no header.
\item[{\texttt{footer}}] If bound, the value must be a valid value of the \texttt{work.footer} component of a browse table, see \texttt{BrowseData.IsBrowseTable} (\ref{BrowseData.IsBrowseTable}); for example, the value can be a list of strings. If this component is not
bound then the browse table has no footer.
\item[{\texttt{convertEntry}}] If bound, the value must be a unary function that returns a string describing
its argument. The default is the operation \texttt{String} (\textbf{Reference: String}). Another possible value is \texttt{NCurses.ReplaceZeroByDot}, which returns the string \texttt{"."} if the argument is a zero element in the sense of \texttt{IsZero} (\textbf{Reference: IsZero}), and returns the \texttt{String} (\textbf{Reference: String}) value otherwise. For each entry in a row of \mbox{\texttt{\mdseries\slshape list}}, the \texttt{convertEntry} value is shown in the browse table.
\item[{\texttt{labelsRow}}] If bound, the value must be a list of row label rows for \mbox{\texttt{\mdseries\slshape list}}, as described in Section \texttt{BrowseData.IsBrowseTable} (\ref{BrowseData.IsBrowseTable}). The default is \texttt{[ [ "1" ], [ "2" ], ... ]}.
\item[{\texttt{labelsCol}}] If bound, the value must be a list of column label rows for \mbox{\texttt{\mdseries\slshape list}}, as described in Section \texttt{BrowseData.IsBrowseTable} (\ref{BrowseData.IsBrowseTable}). The default is \texttt{[ [ "1", "2", ... ] ]}.
\end{description}
The full functionality of the function \texttt{NCurses.BrowseGeneric} (\ref{NCurses.BrowseGeneric}) is available. }
\subsection{\textcolor{Chapter }{Browse (for a list of lists)}}
\logpage{[ 6, 2, 2 ]}\nobreak
\hyperdef{L}{X7AD78A0B7BEDBB20}{}
{\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{Browse({\mdseries\slshape list})\index{Browse@\texttt{Browse}!for a list of lists}
\label{Browse:for a list of lists}
}\hfill{\scriptsize (method)}}\\
\textbf{\indent Returns:\ }
nothing.
Several methods for the operation \texttt{Browse} (\ref{Browse}) are installed for the case that the argument is a list of lists. These methods
cover a default method for lists of lists and the \texttt{Display} (\textbf{Reference: Display}) methods for matrices over finite fields and residue class rings of the
rational integers. Note that matrices over finite prime fields, small
extension fields, and large extension fields are displayed differently, and
the same holds for the corresponding \texttt{Browse} (\ref{Browse}) methods.
\begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=Example]
!gapprompt@gap>| !gapinput@n:= [ 14, 14, 14, 14 ];;|
!gapprompt@gap>| !gapinput@input:= Concatenation( n, n, n, "Q" );; # ``do nothing and quit''|
!gapprompt@gap>| !gapinput@BrowseData.SetReplay( input );|
!gapprompt@gap>| !gapinput@Browse( RandomMat( 10, 10, Integers ) );|
!gapprompt@gap>| !gapinput@BrowseData.SetReplay( input );|
!gapprompt@gap>| !gapinput@Browse( RandomMat( 10, 10, GF(3) ) );|
!gapprompt@gap>| !gapinput@BrowseData.SetReplay( input );|
!gapprompt@gap>| !gapinput@Browse( RandomMat( 10, 10, GF(4) ) );|
!gapprompt@gap>| !gapinput@BrowseData.SetReplay( input );|
!gapprompt@gap>| !gapinput@Browse( RandomMat( 10, 10, Integers mod 6 ) );|
!gapprompt@gap>| !gapinput@BrowseData.SetReplay( input );|
!gapprompt@gap>| !gapinput@Browse( RandomMat( 10, 10, GF( NextPrimeInt( 2^16 ) ) ) );|
!gapprompt@gap>| !gapinput@BrowseData.SetReplay( input );|
!gapprompt@gap>| !gapinput@Browse( RandomMat( 10, 10, GF( 2^20 ) ) );|
!gapprompt@gap>| !gapinput@BrowseData.SetReplay( false );|
\end{Verbatim}
}
}
\section{\textcolor{Chapter }{Character Table Display}}\label{sec:ctbldisp}
\logpage{[ 6, 3, 0 ]}
\hyperdef{L}{X8720923F7FDE5223}{}
{
The \textsf{GAP} library provides a \texttt{Display} (\textbf{Reference: Display}) method for character tables that breaks the table into columns fitting on the
screen. \textsf{Browse} provides an alternative, using the standard facilities of the function \texttt{NCurses.BrowseGeneric} (\ref{NCurses.BrowseGeneric}), i.{\nobreakspace}e., one can scroll in the matrix of character values,
searching and sorting are provided etc.
The \texttt{Browse} (\ref{Browse}) method for character tables can be called instead of \texttt{Display} (\textbf{Reference: Display}). For convenience, one can additionally make this function the default \texttt{Display} (\textbf{Reference: Display}) method for character tables, by assigning it to the \texttt{Display} component in the global record \texttt{CharacterTableDisplayDefaults.User}, see{\nobreakspace} (\textbf{Reference: Printing Character Tables}); for example, one can do this in one's \texttt{gaprc} file, see{\nobreakspace} (\textbf{Reference: The gap.ini and gaprc files}). (This can be undone by unbinding the component \texttt{CharacterTableDisplayDefaults.User.Display}.)
The function \texttt{BrowseDecompositionMatrix} (\ref{BrowseDecompositionMatrix}) can be used to display decomposition matrices for Brauer character tables.
\subsection{\textcolor{Chapter }{Browse (for character tables)}}
\logpage{[ 6, 3, 1 ]}\nobreak
\hyperdef{L}{X870C744182073CF6}{}
{\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{Browse({\mdseries\slshape tbl[, options]})\index{Browse@\texttt{Browse}!for character tables}
\label{Browse:for character tables}
}\hfill{\scriptsize (method)}}\\
This method displays the character table \mbox{\texttt{\mdseries\slshape tbl}} in a window. The optional record \mbox{\texttt{\mdseries\slshape options}} describes what shall be displayed, the supported components and the default
values are described in{\nobreakspace} (\textbf{Reference: Printing Character Tables}).
The full functionality of the function \texttt{NCurses.BrowseGeneric} (\ref{NCurses.BrowseGeneric}) is available.
\begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=Example]
!gapprompt@gap>| !gapinput@if TestPackageAvailability( "CTblLib" ) = true then|
!gapprompt@>| !gapinput@ BrowseData.SetReplay( Concatenation(|
!gapprompt@>| !gapinput@ # scroll in the table|
!gapprompt@>| !gapinput@ "DRULdddddrrrrrlluu",|
!gapprompt@>| !gapinput@ # select an entry and move it around|
!gapprompt@>| !gapinput@ "seddrruuuddlll",|
!gapprompt@>| !gapinput@ # search for the pattern 135 (six times)|
!gapprompt@>| !gapinput@ "/135", [ NCurses.keys.ENTER ], "nnnnn",|
!gapprompt@>| !gapinput@ # deselect the entry, select the first column|
!gapprompt@>| !gapinput@ "qLsc",|
!gapprompt@>| !gapinput@ # sort and categorize by this column|
!gapprompt@>| !gapinput@ "sc",|
!gapprompt@>| !gapinput@ # select the first row, move down the selection|
!gapprompt@>| !gapinput@ "srdddd",|
!gapprompt@>| !gapinput@ # expand the selected category, scroll the selection down|
!gapprompt@>| !gapinput@ "xd",|
!gapprompt@>| !gapinput@ # and quit the application|
!gapprompt@>| !gapinput@ "Q" ) );|
!gapprompt@>| !gapinput@ Browse( CharacterTable( "HN" ) );|
!gapprompt@>| !gapinput@ BrowseData.SetReplay( false );|
!gapprompt@>| !gapinput@fi;|
\end{Verbatim}
\emph{Implementation remarks}: The first part of the code in the \texttt{Browse} (\ref{Browse}) method for character tables is almost identical with the code for extracting
the data to be displayed from the input data in the \textsf{GAP} library function \texttt{CharacterTableDisplayDefault}. The second part of the code transforms these data into a browse table.
Character names and (if applicable) indicator values are used as row labels,
and centralizer orders, power maps, and class names are used as column labels.
The identifier of the table is used as the static header. When an irrational
entry is selected, a description of this entry is shown in the dynamic footer.
The standard modes in \texttt{BrowseData} (\ref{BrowseData}) (except the \texttt{help} mode) have been extended by three new actions. The first two of them open
pagers giving an overview of all irrationalities in the table, or of all those
irrationalities that have been shown on the screen in the current call,
respectively. The corresponding user inputs are the \textsc{I} and the \textsc{i} key. (The names assigned to the irrationalities are generated column-wise. If
one just scrolls through the table, without jumping, then these names coincide
with the names generated by the default \texttt{Display} (\textbf{Reference: Display}) method for character tables; this is in general \emph{not} the case, for example when a row-wise search in the table is performed.) The
third new action, which is associated with the \textsc{p} key, toggles the visibility status of the column label rows for centralizer
orders and power maps.
An individual \texttt{minyx} function does not only check whether the desired table fits into the window
but also whether a table with too high column labels (centralizer orders and
power maps) would fit if these labels get collapsed via the \textsc{p} key. In this case, the labels are automatically collapsed, and the \textsc{p} key is disabled.
In order to keep the required space small also for large character tables,
caching of formatted matrix entries is disabled, and the strings to be
displayed are computed on demand with a \texttt{Main} function in the \texttt{work} component of the browse table. For the same reason, the constant height one
for all table rows is set in advance, so one need not inspect a whole
character if only a few values of it shall be shown.
Special functions are provided for sorting (concerning the comparison of
character values, which can be integers or irrationalities) and categorizing
the table by a column (the value in the category row involves the class name
of the column in question).
The code can be found in the file \texttt{app/ctbldisp.g} of the package. }
\subsection{\textcolor{Chapter }{BrowseDecompositionMatrix}}
\logpage{[ 6, 3, 2 ]}\nobreak
\hyperdef{L}{X7D80A56D853C9655}{}
{\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{BrowseDecompositionMatrix({\mdseries\slshape modtbl[, b][, options]})\index{BrowseDecompositionMatrix@\texttt{BrowseDecompositionMatrix}}
\label{BrowseDecompositionMatrix}
}\hfill{\scriptsize (function)}}\\
This method displays the decomposition matrix of (the \mbox{\texttt{\mdseries\slshape b}}-th block of) the Brauer character table \mbox{\texttt{\mdseries\slshape modtbl}} in a window. The arguments are the same as for \texttt{LaTeXStringDecompositionMatrix} (\textbf{Reference: LaTeXStringDecompositionMatrix}).
The positions of the ordinary and modular irreducible characters are shown in
the labels of the rows and columns, respectively, that are indexed by these
characters. When an entry in the decomposition matrix is selected then
information about the degrees of these characters is shown in the table
footer.
The full functionality of the function \texttt{NCurses.BrowseGeneric} (\ref{NCurses.BrowseGeneric}) is available.
\begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=Example]
!gapprompt@gap>| !gapinput@BrowseData.SetReplay( Concatenation(|
!gapprompt@>| !gapinput@ # select the first entry|
!gapprompt@>| !gapinput@ "se",|
!gapprompt@>| !gapinput@ # scroll in the table|
!gapprompt@>| !gapinput@ "drrrr",|
!gapprompt@>| !gapinput@ # keep the table open for a while|
!gapprompt@>| !gapinput@ [ 14, 14, 14, 14, 14 ],|
!gapprompt@>| !gapinput@ # and quit the application|
!gapprompt@>| !gapinput@ "Q" ) );|
!gapprompt@gap>| !gapinput@BrowseDecompositionMatrix( CharacterTable( "J1" ) mod 2 );|
!gapprompt@gap>| !gapinput@BrowseData.SetReplay( false );|
\end{Verbatim}
The code can be found in the file \texttt{app/ctbldisp.g} of the package. }
}
\section{\textcolor{Chapter }{Table of Marks Display}}\label{sec:tomdisp}
\logpage{[ 6, 4, 0 ]}
\hyperdef{L}{X80E9A03780DE8891}{}
{
The \textsf{GAP} library provides a \texttt{Display} (\textbf{Reference: Display}) method for tables of marks that breaks the table into columns fitting on the
screen. Similar to the situation with character tables, see
Section{\nobreakspace}\ref{sec:ctbldisp}, but with a much simpler implementation, \textsf{Browse} provides an alternative based on the function \texttt{NCurses.BrowseGeneric} (\ref{NCurses.BrowseGeneric}).
\texttt{Browse} (\ref{Browse}) can be called instead of \texttt{Display} (\textbf{Reference: Display}) for tables of marks, cf.{\nobreakspace} (\textbf{Reference: Printing Tables of Marks}).
\subsection{\textcolor{Chapter }{Browse (for tables of marks)}}
\logpage{[ 6, 4, 1 ]}\nobreak
\hyperdef{L}{X7F4BD9C580BBBAA4}{}
{\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{Browse({\mdseries\slshape tom[, options]})\index{Browse@\texttt{Browse}!for tables of marks}
\label{Browse:for tables of marks}
}\hfill{\scriptsize (method)}}\\
This method displays the table of marks \mbox{\texttt{\mdseries\slshape tom}} in a window. The optional record \mbox{\texttt{\mdseries\slshape options}} describes what shall be displayed, the supported components and the default
values are described in{\nobreakspace} (\textbf{Reference: Printing Tables of Marks}).
The full functionality of the function \texttt{NCurses.BrowseGeneric} (\ref{NCurses.BrowseGeneric}) is available.
\begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=Example]
!gapprompt@gap>| !gapinput@if TestPackageAvailability( "TomLib" ) = true then|
!gapprompt@>| !gapinput@ BrowseData.SetReplay( Concatenation(|
!gapprompt@>| !gapinput@ # scroll in the table|
!gapprompt@>| !gapinput@ "DDRRR",|
!gapprompt@>| !gapinput@ # search for the (exact) value 100 (three times)|
!gapprompt@>| !gapinput@ "/100",|
!gapprompt@>| !gapinput@ [ NCurses.keys.DOWN, NCurses.keys.DOWN, NCurses.keys.RIGHT ],|
!gapprompt@>| !gapinput@ [ NCurses.keys.DOWN, NCurses.keys.DOWN, NCurses.keys.DOWN ],|
!gapprompt@>| !gapinput@ [ NCurses.keys.RIGHT, NCurses.keys.ENTER ], "nn",|
!gapprompt@>| !gapinput@ # no more occurrences of 100, confirm|
!gapprompt@>| !gapinput@ [ NCurses.keys.ENTER ],|
!gapprompt@>| !gapinput@ # and quit the application|
!gapprompt@>| !gapinput@ "Q" ) );|
!gapprompt@>| !gapinput@ Browse( TableOfMarks( "A10" ) );|
!gapprompt@>| !gapinput@ BrowseData.SetReplay( false );|
!gapprompt@>| !gapinput@ fi;|
\end{Verbatim}
\emph{Implementation remarks}: Rows and columns are indexed by their positions. The identifier of the table
is used as the static header, there is no footer.
In order to keep the required space small also for large tables of marks,
caching of formatted matrix entries is disabled, and the strings to be
displayed are computed on demand with a \texttt{Main} function in the \texttt{work} component of the browse table. For the same reason, the constant height one
for the table rows is set in advance. (For example, the table of marks of the
group with identifier \texttt{"O8+(2)"}, with $11171$ rows and columns, can be shown with \texttt{Browse} (\ref{Browse}) in a \textsf{GAP} session requiring about $100$ MB.)
The code can be found in the file \texttt{app/tomdisp.g} of the package. }
}
\section{\textcolor{Chapter }{Table of Contents of \textsf{AtlasRep}}}\label{sec:atlasdisp}
\logpage{[ 6, 5, 0 ]}
\hyperdef{L}{X80370827793813FD}{}
{
The \textsf{GAP} package \textsf{AtlasRep} (see{\nobreakspace}\cite{AtlasRep}) is an interface to a database of representations and related data. The table
of contents of this database can be displayed via the function \texttt{DisplayAtlasInfo} (\textbf{AtlasRep: DisplayAtlasInfo}) of this package. The \textsf{Browse} package provides an alternative based on the function \texttt{NCurses.BrowseGeneric} (\ref{NCurses.BrowseGeneric}); one can scroll, search, and fetch data for later use.
\subsection{\textcolor{Chapter }{BrowseAtlasInfo}}\logpage{[ 6, 5, 1 ]}
\hyperdef{L}{X8411AF928194C5AB}{}
{
\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{BrowseAtlasInfo({\mdseries\slshape [listofnames][,] ["contents", sources][,] [...]})\index{BrowseAtlasInfo@\texttt{BrowseAtlasInfo}!overview of groups}
\label{BrowseAtlasInfo:overview of groups}
}\hfill{\scriptsize (function)}}\\
\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{BrowseAtlasInfo({\mdseries\slshape gapname[, std][, ...]})\index{BrowseAtlasInfo@\texttt{BrowseAtlasInfo}!overview for one group}
\label{BrowseAtlasInfo:overview for one group}
}\hfill{\scriptsize (function)}}\\
\textbf{\indent Returns:\ }
the list of ``clicked'' info records.
This function shows the information available via the \textsf{GAP} package \textsf{AtlasRep} in a browse table, cf. Section{\nobreakspace} (\textbf{AtlasRep: Accessing Data via AtlasRep}) in the \textsf{AtlasRep} manual.
The optional arguments can be used to restrict the table to core data or data
extensions, or to show an overview for one particular group. The arguments are
the same as for \texttt{DisplayAtlasInfo} (\textbf{AtlasRep: DisplayAtlasInfo}), see the documentation of this function for details. (Note that additional
conditions such as \texttt{IsPermGroup} (\textbf{Reference: IsPermGroup}) can be entered also in the case that no \mbox{\texttt{\mdseries\slshape gapname}} is given. In this situation, the additional conditions are evaluated for the ``second level tables'' that are opened by ``clicking'' on a table row or entry.)
When one ``clicks'' on one of the table rows or entries then a browse table with an overview of
the information available for this group is shown, and ``clicking'' on one of the rows in these tables adds the corresponding info record (see \texttt{OneAtlasGeneratingSetInfo} (\textbf{AtlasRep: OneAtlasGeneratingSetInfo})) to the list of return values of \texttt{BrowseAtlasInfo}.
The full functionality of the function \texttt{NCurses.BrowseGeneric} (\ref{NCurses.BrowseGeneric}) is available.
The following example shows how \texttt{BrowseAtlasInfo} can be used to fetch info records about permutation representations of the
alternating groups $A_5$ and $A_6$: We search for the group name \texttt{"A5"} in the overview table, and the first cell in the table row for $A_5$ becomes selected; hitting the \textsc{Enter} key causes a new window to be opened, with an overview of the data available
for $A_5$; moving down two rows and hitting the \textsc{Enter} key again causes the second representation to be added to the result list;
hitting \textsc{Q} closes the second window, and we are back in the overview table; we move the
selection down twice (to the row for the group $A_6$), and choose the first representation for this group; finally we leave the
table, and the return value is the list with the data for the two
representations.
\begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=Example]
!gapprompt@gap>| !gapinput@d:= [ NCurses.keys.DOWN ];; r:= [ NCurses.keys.RIGHT ];;|
!gapprompt@gap>| !gapinput@c:= [ NCurses.keys.ENTER ];;|
!gapprompt@gap>| !gapinput@BrowseData.SetReplay( Concatenation(|
!gapprompt@>| !gapinput@ "/A5", # Find the string A5 ...|
!gapprompt@>| !gapinput@ d, d, r, # ... such that just the word matches,|
!gapprompt@>| !gapinput@ c, # start the search,|
!gapprompt@>| !gapinput@ c, # click the table entry A5,|
!gapprompt@>| !gapinput@ d, d, # move down two rows,|
!gapprompt@>| !gapinput@ c, # click the row for this representation,|
!gapprompt@>| !gapinput@ "Q", # quit the second level table,|
!gapprompt@>| !gapinput@ d, d, # move down two rows,|
!gapprompt@>| !gapinput@ c, # click the table entry A6,|
!gapprompt@>| !gapinput@ d, # move down one row,|
!gapprompt@>| !gapinput@ c, # click the first row,|
!gapprompt@>| !gapinput@ "Q", # quit the second level table,|
!gapprompt@>| !gapinput@ "Q" ) ); # and quit the application.|
!gapprompt@gap>| !gapinput@if IsBound( BrowseAtlasInfo ) and IsBound( AtlasProgramInfo ) then|
!gapprompt@>| !gapinput@ SetUserPreference( "AtlasRep", "AtlasRepMarkNonCoreData", "" );|
!gapprompt@>| !gapinput@ tworeps:= BrowseAtlasInfo();|
!gapprompt@>| !gapinput@ else|
!gapprompt@>| !gapinput@ tworeps:= [ fail ];|
!gapprompt@>| !gapinput@ fi;|
!gapprompt@gap>| !gapinput@BrowseData.SetReplay( false );|
!gapprompt@gap>| !gapinput@if fail in tworeps then|
!gapprompt@>| !gapinput@ Print( "no access to the Web ATLAS\n" );|
!gapprompt@>| !gapinput@ else|
!gapprompt@>| !gapinput@ Print( List( tworeps, x -> x.identifier[1] ), "\n" );|
!gapprompt@>| !gapinput@ fi;|
[ "A5", "A6" ]
\end{Verbatim}
\emph{Implementation remarks}: The first browse table shown has a static header, no footer and row labels,
one row of column labels describing the type of data summarized in the
columns.
Row and column separators are drawn as grids (cf.{\nobreakspace}\texttt{NCurses.Grid} (\ref{NCurses.Grid})) composed from the special characters described in Section{\nobreakspace}\ref{ssec:ncursesLines}, using the component \texttt{work.SpecialGrid} of the browse table, see \texttt{BrowseData} (\ref{BrowseData}).
When a row is selected, the ``click'' functionality opens a new window (via a second level call to \texttt{NCurses.BrowseGeneric} (\ref{NCurses.BrowseGeneric})), in which a browse table with the list of available data for the given group
is shown; in this table, ``click'' results in adding the info for the selected row to the result list, and a
message about this addition is shown in the footer row. One can choose further
data, return to the first browse table, and perhaps iterate the process for
other groups. When the first level table is left, the list of info records for
the chosen data is returned.
For the two kinds of browse tables, the standard modes in \texttt{BrowseData} (\ref{BrowseData}) (except the \texttt{help} mode) have been extended by a new action that opens a pager giving an overview
of all data that have been chosen in the current call. The corresponding user
input is the \textsc{Y} key.
This function is available only if the \textsf{GAP} package \textsf{AtlasRep} is available.
The code can be found in the file \texttt{app/atlasbrowse.g} of the package. }
}
\section{\textcolor{Chapter }{Access to \textsf{GAP} Manuals{\textendash}a Variant}}\label{sec:manualdisp}
\logpage{[ 6, 6, 0 ]}
\hyperdef{L}{X7CF999297B331E01}{}
{
A \textsf{Browse} adapted way to access several manuals is to show the hierarchy of books,
chapters, sections, and subsections as collapsible category rows, and to
regard the contents of each subsection as a data row of a matrix with only one
column.
This application is mainly intended as an example with table cells that exceed
the screen, and as an example with several category levels.
\subsection{\textcolor{Chapter }{BrowseGapManuals}}
\logpage{[ 6, 6, 1 ]}\nobreak
\hyperdef{L}{X7D79DF9181A15EDF}{}
{\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{BrowseGapManuals({\mdseries\slshape [start]})\index{BrowseGapManuals@\texttt{BrowseGapManuals}}
\label{BrowseGapManuals}
}\hfill{\scriptsize (function)}}\\
This function displays the contents of the \textsf{GAP} manuals (the main \textsf{GAP} manuals as well as the loaded package manuals) in a window. The optional
argument \mbox{\texttt{\mdseries\slshape start}} describes the initial status, admissible values are the strings \texttt{"inline/collapsed"}, \texttt{"inline/expanded"}, \texttt{"pager/collapsed"}, and \texttt{"pager/expanded"}.
In the \texttt{inline} cases, the parts of the manuals are shown in the browse table, and in the \texttt{pager} case, the parts of the manuals are shown in a different window when they are ``clicked'', using the user's favourite help viewer, see (\textbf{Reference: Changing the Help Viewer}).
In the \texttt{collapsed} cases, all category rows are collapsed, and the first row is selected; typical
next steps are moving down the selection and expanding single category rows.
In the \texttt{expanded} cases, all category rows are expanded, and nothing is selected; a typical next
step in the \texttt{inline/expanded} case is a search for a string in the manuals. (Note that searching in quite
slow: For viewing a part of a manual, the file with the corresponding section
is read into \textsf{GAP}, the text is formatted, the relevant part is cut out from the section,
perhaps markup is stripped off, and finally the search is performed in the
resulting strings.)
If no argument is given then the user is asked for selecting an initial
status, using \texttt{NCurses.Select} (\ref{NCurses.Select}).
The full functionality of the function \texttt{NCurses.BrowseGeneric} (\ref{NCurses.BrowseGeneric}) is available.
\begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=Example]
!gapprompt@gap>| !gapinput@n:= [ 14, 14, 14 ];; # ``do nothing''|
!gapprompt@gap>| !gapinput@BrowseData.SetReplay( Concatenation(|
!gapprompt@>| !gapinput@ "xdxd", # expand a Tutorial section|
!gapprompt@>| !gapinput@ n, "Q" ) ); # and quit|
!gapprompt@gap>| !gapinput@BrowseGapManuals( "inline/collapsed" );|
!gapprompt@gap>| !gapinput@BrowseData.SetReplay( Concatenation(|
!gapprompt@>| !gapinput@ "/Browse", [ NCurses.keys.ENTER ], # search for "Browse"|
!gapprompt@>| !gapinput@ "xdxddxd", # expand a section|
!gapprompt@>| !gapinput@ n, "Q" ) ); # and quit|
!gapprompt@gap>| !gapinput@BrowseGapManuals( "inline/collapsed" );|
!gapprompt@gap>| !gapinput@BrowseData.SetReplay( false );|
\end{Verbatim}
\emph{Implementation remarks}: The browse table has a dynamic header showing the name of the currently
selected manual, no footer, no row or column labels, and exactly one column of
fixed width equal to the screen width. The category rows are precomputed,
i.{\nobreakspace}e., they do not arise from a table column; this way, the
contents of each data cell can be computed on demand, as soon as it is shown
on the screen, in particular the category hierarchy is computed without
reading the manuals into \textsf{GAP}. Also, the data rows are not cached. There is no return value. The heights of
many cells are bigger than the screen height, so scrolling is a mixture of
scrolling to the next cell and scrolling inside a cell. The different initial
states are realized via executing different initial steps before the table is
shown to the user.
For the variants that show the manuals in a pager, the code temporarily
replaces the \texttt{show} function of the default viewer \texttt{"screen"} (see (\textbf{Reference: Changing the Help Viewer})) by a function that uses \texttt{NCurses.Pager} (\ref{NCurses.Pager}). Note that in the case that the manual bit in question fits into one screen,
the default \texttt{show} function writes this text directly to the screen, but this is used already by
the browse table.
The implementation should be regarded as a sketch.
For example, the markup available in the text file format of \textsf{GAPDoc} manuals (using \textsc{Esc} sequences) is stripped off instead of being transferred to the attribute lines
that arise, because of the highlighting problem mentioned in
Section{\nobreakspace}\ref{NCurses.IsAttributeLine}.
Some heuristics used in the code are due to deficiencies of the manual
formats.
For the inline variant of the browse table, the titles of chapters, sections,
and subsections are \emph{not} regarded as parts of the actual text since they appear already as category
rows; however, the functions of the \textsf{GAP} help system deliver the text \emph{together with} these titles, so these lines must be stripped off afterwards.
The category hierarchy representing the tables of contents is created from the \texttt{manual.six} files of the manuals. These files do not contain enough information for
determining whether several functions define the same subsection, in the sense
that there is a common description text after a series of manual lines
introducing different functions. In such cases, the browse table contains a
category row for each of these functions (with its own number), but the
corresponding text appears only under the \emph{last} of these category rows, the data rows for the others are empty. (This problem
does not occur in the \textsf{GAPDoc} manual format because this introduces explicit subsection titles, involving
only the \emph{first} of several function definitions.)
Also, index entries and sectioning entries in \texttt{manual.six} files of manuals in \textsf{GAPDoc} format are not explicitly distinguished.
The code can be found in the file \texttt{app/manual.g} of the package. }
}
\section{\textcolor{Chapter }{Overview of Bibliographies}}\label{sec:gapbibl}
\logpage{[ 6, 7, 0 ]}
\hyperdef{L}{X846751CC7F54F51D}{}
{
The function \texttt{BrowseBibliography} (\ref{BrowseBibliography}) can be used to turn the contents of bibliography files in BibTeX or BibXMLext
format (see (\textbf{GAPDoc: The BibXMLext Format})) into a Browse table, such that one can scroll in the list, search for
entries, sort by year, sort and categorize by authors etc.
The default bibliography used by \texttt{BrowseBibliography} (\ref{BrowseBibliography}) is the bibliography of \textsf{GAP} related publications, see{\nobreakspace}\cite{GAPBibliography}. The \textsf{Browse} package contains a (perhaps outdated) version of this bibliography. One can
get an updated version as follows.
\texttt{wget -N http://www.gap-system.org/Doc/Bib/gap-publishednicer.bib}
The columns of the Browse table that is shown by \texttt{BrowseBibliography} (\ref{BrowseBibliography}) can be customized, two examples for that are given by the functions \texttt{BrowseBibliographySporadicSimple} (\textbf{AtlasRep: BrowseBibliographySporadicSimple}) and \texttt{BrowseBibliographyGapPackages} (\ref{BrowseBibliographyGapPackages}).
The function \texttt{BrowseMSC} (\ref{BrowseMSC}) shows an overview of the AMS Mathematics Subject Classification codes.
\subsection{\textcolor{Chapter }{BrowseBibliography}}
\logpage{[ 6, 7, 1 ]}\nobreak
\hyperdef{L}{X7F0FE4CC7F46ABF3}{}
{\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{BrowseBibliography({\mdseries\slshape [bibfiles]})\index{BrowseBibliography@\texttt{BrowseBibliography}}
\label{BrowseBibliography}
}\hfill{\scriptsize (function)}}\\
\textbf{\indent Returns:\ }
a record as returned by \texttt{ParseBibXMLExtFiles} (\textbf{GAPDoc: ParseBibXMLextFiles}).
This function shows the list of bibliography entries in the files given by \mbox{\texttt{\mdseries\slshape bibfiles}}, which may be a string or a list of strings (denoting a filename or a list of
filenames, respectively) or a record (see below for the supported components).
If no argument is given then the file \texttt{bibl/gap-publishednicer.bib} in the \textsf{Browse} package directory is taken, and \texttt{"GAP Bibliography"} is used as the header.
Another perhaps interesting data file that should be available in the \textsf{GAP} distribution is \texttt{doc/manualbib.xml}. This file can be located as follows.
\begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=Example]
!gapprompt@gap>| !gapinput@file:= Filename( DirectoriesLibrary( "doc" ), "manualbib.xml" );;|
\end{Verbatim}
Both Bib{\TeX} format and the \textsf{XML} based extended format provided by the \textsf{GAPDoc} package are supported by \texttt{BrowseBibliography}, see Chapter{\nobreakspace} (\textbf{GAPDoc: Utilities for Bibliographies}).
In the case of Bib{\TeX} format input, first a conversion to the extended format takes place, via \texttt{StringBibAsXMLext} (\textbf{GAPDoc: StringBibAsXMLext}) and \texttt{ParseBibXMLextString} (\textbf{GAPDoc: ParseBibXMLextString}). Note that syntactically incorrect entries are rejected in this conversion
{\textendash}this is signaled with \texttt{InfoBibTools} (\textbf{GAPDoc: InfoBibTools}) warnings{\textendash} and that only a subset of the possible {\LaTeX} markup is recognized {\textendash}other markup appears in the browse table
except that the leading backslash is removed.
In both cases of input, the problem arises that in visual mode, currently we
can show only ASCII characters (and the symbols in \texttt{NCurses.lineDraw}, but these are handled differently, see Section{\nobreakspace}\ref{ssec:ncursesLines}). Therefore, we use the function \texttt{SimplifiedUnicodeString} (\textbf{GAPDoc: SimplifiedUnicodeString}) for replacing other unicode characters by ASCII text.
The return value is a record as returned by \texttt{ParseBibXMLExtFiles} (\textbf{GAPDoc: ParseBibXMLextFiles}), its \texttt{entries} component corresponds to the bibliography entries that have been ``clicked'' in visual mode. This record can be used as input for \texttt{WriteBibFile} (\textbf{GAPDoc: WriteBibFile}) or \texttt{WriteBibXMLextFile} (\textbf{GAPDoc: WriteBibXMLextFile}), in order to produce a bibliography file, or it can be used as input for \texttt{StringBibXMLEntry} (\textbf{GAPDoc: StringBibXMLEntry}), in order to produce strings from the entries, in various formats.
The full functionality of the function \texttt{NCurses.BrowseGeneric} (\ref{NCurses.BrowseGeneric}) is available.
\begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=Example]
!gapprompt@gap>| !gapinput@# sort and categorize by year, scroll down, expand a category row|
!gapprompt@gap>| !gapinput@BrowseData.SetReplay( "scrrscsedddddxdddddQ" );|
!gapprompt@gap>| !gapinput@BrowseBibliography();;|
!gapprompt@gap>| !gapinput@# sort & categorize by authors, expand all category rows, scroll down|
!gapprompt@gap>| !gapinput@BrowseData.SetReplay( "scscXseddddddQ" );|
!gapprompt@gap>| !gapinput@BrowseBibliography();;|
!gapprompt@gap>| !gapinput@# sort and categorize by journal, search for a journal name, expand|
!gapprompt@gap>| !gapinput@BrowseData.SetReplay( Concatenation( "scrrrsc/J. Algebra",|
!gapprompt@>| !gapinput@ [ NCurses.keys.ENTER ], "nxdddQ" ) );|
!gapprompt@gap>| !gapinput@BrowseBibliography();;|
!gapprompt@gap>| !gapinput@BrowseData.SetReplay( false );|
\end{Verbatim}
\emph{Implementation remarks}: The browse table has a dynamic header (showing the number of entries, which
can vary when the table is restricted), no footer and row labels; one row of
column labels is given by the descriptions of the table columns (authors,
title, year, journal, MSC code).
Row and column separators are drawn as grids (cf.{\nobreakspace}\texttt{NCurses.Grid} (\ref{NCurses.Grid})) composed from the special characters described in Section{\nobreakspace}\ref{ssec:ncursesLines}, using the component \texttt{work.SpecialGrid} of the browse table, see \texttt{BrowseData} (\ref{BrowseData}).
For categorizing by authors (or by MSC codes), the sort parameter \texttt{"split rows on categorizing"} is set to \texttt{"yes"}, so the authors (codes) are distributed to different category rows, hence
each entry appears once for each of its authors (or its MSC codes) in the
categorized table. When a data row or an entry in a data row is selected, ``click'' adds the corresponding bibliographhy entry to the result.
The width of the title column is preset; usually titles are too long for one
line, and the contents of this column is formatted as a paragraph, using the
function \texttt{FormatParagraph} (\textbf{GAPDoc: FormatParagraph}). For the authors and journal columns, maximal widths are prescribed, and \texttt{FormatParagraph} (\textbf{GAPDoc: FormatParagraph}) is used for longer entries.
For four columns, the sort parameters are defined as follows: The \emph{authors} and \emph{MSC code} columns do not become hidden when the table is categorized according to this
column, sorting by the \emph{year} yields a \emph{de}scending order, and the category rows arising from these columns and the \emph{journal} column show the numbers of the data rows that belong to them.
Those standard modes in \texttt{BrowseData} (\ref{BrowseData}) where an entry or a row of the table is selected have been extended by three
new actions, which open a pager showing the Bib{\TeX}, HTML, and Text format of the selected entry, respectively. The corresponding
user inputs are the \textsc{vb}, \textsc{vh}, and \textsc{vt}. If the \emph{MSC code} column is available then also the user input \textsc{vm} is admissible; it opens a pager showing the descriptions of the MSC codes
attached to the selected entry.
This function requires some of the utilities provided by the \textsf{GAP} package \textsf{GAPDoc} (see{\nobreakspace}\cite{GAPDoc}), such as \texttt{FormatParagraph} (\textbf{GAPDoc: FormatParagraph}), \texttt{NormalizeNameAndKey} (\textbf{GAPDoc: NormalizeNameAndKey}), \texttt{NormalizedNameAndKey} (\textbf{GAPDoc: NormalizedNameAndKey}), \texttt{ParseBibFiles} (\textbf{GAPDoc: ParseBibFiles}), \texttt{ParseBibXMLextFiles} (\textbf{GAPDoc: ParseBibXMLextFiles}), \texttt{ParseBibXMLextString} (\textbf{GAPDoc: ParseBibXMLextString}), \texttt{RecBibXMLEntry} (\textbf{GAPDoc: RecBibXMLEntry}), and \texttt{StringBibAsXMLext} (\textbf{GAPDoc: StringBibAsXMLext}).
The code can be found in the file \texttt{app/gapbibl.g} of the package.
The browse table can be customized by entering a record as the argument of \texttt{BrowseBibliography}, with the following supported components.
\begin{description}
\item[{\texttt{files}}] a nonempty list of filenames containing the data to be shown; there is no
default for this component.
\item[{\texttt{filesshort}}] a list of the same length as the \texttt{files} component, the entries are strings which are shown in the \texttt{"sourcefilename"} column of the table (if this column is present); the default is the list of
filenames.
\item[{\texttt{filecontents}}] a list of the same length as the \texttt{files} component, the entries are strings which are shown as category values when the
table is categorized by the \texttt{"sourcefilename"} column; the default is the list of filenames.
\item[{\texttt{header}}] is the constant part of the header shown above the browse table, the default
is the first filename.
\item[{\texttt{columns}}] is a list of records that are valid as the second argument of \texttt{DatabaseAttributeAdd} (\ref{DatabaseAttributeAdd}), where the first argument is a database id enumerator created from the
bibliography entries in the files in question. Each entry (and also the
corresponding identifier) of this database id enumerator is a list of records
obtained from \texttt{ParseBibXMLextFiles} (\textbf{GAPDoc: ParseBibXMLextFiles}) and \texttt{RecBibXMLEntry} (\textbf{GAPDoc: RecBibXMLEntry}), or from \texttt{ParseBibFiles} (\textbf{GAPDoc: ParseBibFiles}), such that the list elements are regarded as equal, in the sense that their
fingerprints (see below) are equal. The records in the \texttt{columns} list are available for constructing the desired browse table, the actual
appearance is controlled by the \texttt{choice} component described below. Columns showing authors, title, year, journal, MSC
code, and filename are predefined and need not be listed here.
\item[{\texttt{choice}}] a list of strings denoting the \texttt{identifier} components of those columns that shall actually be shown in the table, the
default is \texttt{[ "authors", "title", "year", "journal", "mrclass" ]}.
\item[{\texttt{fingerprint}}] a list of strings denoting component names of the entries of the database id
enumerator that is constructed from the data (see above); two data records are
regarded as equal if the values of these components are equal; the default is \texttt{[ "mrnumber", "title", "authorAsList", "editorAsList", "author" ]}.
\item[{\texttt{sortKeyFunction}}] either \texttt{fail} or a function that takes a record as returned by \texttt{RecBibXMLEntry} (\textbf{GAPDoc: RecBibXMLEntry}) and returns a list that is used for comparing and thus sorting the records;
the default is \texttt{fail}, which means that the rows of the table appear in the same ordering as in the
source files.
\end{description}
}
\subsection{\textcolor{Chapter }{BrowseBibliographyGapPackages}}
\logpage{[ 6, 7, 2 ]}\nobreak
\hyperdef{L}{X7E4B5E277D08987B}{}
{\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{BrowseBibliographyGapPackages({\mdseries\slshape })\index{BrowseBibliographyGapPackages@\texttt{BrowseBibliographyGapPackages}}
\label{BrowseBibliographyGapPackages}
}\hfill{\scriptsize (function)}}\\
\textbf{\indent Returns:\ }
a record as returned by \texttt{BrowseBibliography} (\ref{BrowseBibliography}).
This function collects the information from the \texttt{*.bib} and \texttt{*bib.xml} files in those subdirectories of installed \textsf{GAP} packages which contain the package documentation, and shows it in a Browse
table, using the function \texttt{BrowseBibliography} (\ref{BrowseBibliography}).
\emph{This function is experimental.} The result is not really satisfactory, for the following reasons.
\begin{itemize}
\item Duplicate entries may occur, due to subtle differences in various source
files.
\item The source files may contain more than what is actually cited in the package
manuals.
\item It may happen that some \texttt{*.bib} or \texttt{*bib.xml} file is accidentally distributed with the package but is not intended to serve
as package bibliography.
\item The heuristics for rewriting {\LaTeX} code is of course not perfect; thus strange symbols may occur in the Browse
table.
\end{itemize}
}
\subsection{\textcolor{Chapter }{BrowseMSC}}
\logpage{[ 6, 7, 3 ]}\nobreak
\hyperdef{L}{X81F1558678ACDB4A}{}
{\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{BrowseMSC({\mdseries\slshape [version]})\index{BrowseMSC@\texttt{BrowseMSC}}
\label{BrowseMSC}
}\hfill{\scriptsize (function)}}\\
\textbf{\indent Returns:\ }
nothing.
This function shows the valid MSC codes in a browse table that is categorized
by the \texttt{..-XX} and the \texttt{...xx} codes. (Use \textsc{X} for expanding all categories or \textsc{x} for expanding the currently selected category.) Due to the categorization,
only two columns of the table are visible, showing the codes and their
descriptions.
If \mbox{\texttt{\mdseries\slshape version}} is given then it must be one of the numbers $2010$ or $2020$, meaning that the MSC2010 or MSC2020 codes are shown; the default for \mbox{\texttt{\mdseries\slshape version}} is $2020$. }
}
\section{\textcolor{Chapter }{Profiling \textsf{GAP} functions{\textendash}a Variant}}\label{sec:profiledisp}
\logpage{[ 6, 8, 0 ]}
\hyperdef{L}{X837BDF547FF0EA31}{}
{
A \textsf{Browse} adapted way to evaluate profiling results is to show the overview that is
printed by the \textsf{GAP} function \texttt{DisplayProfile} (\textbf{Reference: DisplayProfile}) in a \textsf{Browse} table, which allows one to sort the profiled functions according to the
numbers of calls, the time spent, etc., and to search for certain functions
one is interested in.
\subsection{\textcolor{Chapter }{BrowseProfile}}
\logpage{[ 6, 8, 1 ]}\nobreak
\hyperdef{L}{X7B42091982DE7AE7}{}
{\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{BrowseProfile({\mdseries\slshape [functions][,] [mincount, mintime]})\index{BrowseProfile@\texttt{BrowseProfile}}
\label{BrowseProfile}
}\hfill{\scriptsize (function)}}\\
The arguments and their meaning are the same as for the function \texttt{DisplayProfile} (\textbf{Reference: DisplayProfile}), in the sense that the lines printed by that function correspond to the rows
of the list that is shown by \texttt{BrowseProfile}. Initially, the table is sorted in the same way as the list shown by \texttt{BrowseProfile}; sorting the table by any of the first five columns will yield a
non-increasing order of the rows.
The threshold values \mbox{\texttt{\mdseries\slshape mincount}} and \mbox{\texttt{\mdseries\slshape mintime}} can be changed in visual mode via the user input \textsc{e}. If mouse events are enabled (see \texttt{NCurses.UseMouse} (\ref{NCurses.UseMouse})) then one can also use a mouse click on the current parameter value shown in
the table header in order to enter the mode for changing the parameters.
When a row or an entry in a row is selected, ``click'' shows the code of the corresponding function in a pager (see \texttt{NCurses.Pager} (\ref{NCurses.Pager})) whenever this is possible, as follows. If the function was read from a file
then this file is opened, if the function was entered interactively then the
code of the function is shown in the format produced by \texttt{Print} (\textbf{Reference: Print}); other functions (for example \textsf{GAP} kernel functions) cannot be shown, one gets an alert message (see \texttt{NCurses.Alert} (\ref{NCurses.Alert})) in such a case.
The full functionality of the function \texttt{NCurses.BrowseGeneric} (\ref{NCurses.BrowseGeneric}) is available.
\begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=Example]
!gapprompt@gap>| !gapinput@n:= [ 14, 14, 14, 14, 14 ];; # ``do nothing''|
!gapprompt@gap>| !gapinput@ProfileOperationsAndMethods( true ); # collect some data|
!gapprompt@gap>| !gapinput@ConjugacyClasses( PrimitiveGroup( 24, 1 ) );;|
!gapprompt@gap>| !gapinput@ProfileOperationsAndMethods( false );|
!gapprompt@gap>| !gapinput@BrowseData.SetReplay( Concatenation(|
!gapprompt@>| !gapinput@ "e", # edit threshold paras|
!gapprompt@>| !gapinput@ [ NCurses.keys.DC ], "2", "\t", # replace 10000 by 20000|
!gapprompt@>| !gapinput@ [ NCurses.keys.DC ], "2", # replace 30 by 20|
!gapprompt@>| !gapinput@ [ NCurses.keys.ENTER ], # commit the changes|
!gapprompt@>| !gapinput@ "scso", # sort by column 1,|
!gapprompt@>| !gapinput@ n,|
!gapprompt@>| !gapinput@ "rso", # sort by column 2,|
!gapprompt@>| !gapinput@ n,|
!gapprompt@>| !gapinput@ "rso", # sort by column 3,|
!gapprompt@>| !gapinput@ n,|
!gapprompt@>| !gapinput@ "q", # deselect the column,|
!gapprompt@>| !gapinput@ "/Normalizer", [ NCurses.keys.ENTER ], # search for a function,|
!gapprompt@>| !gapinput@ n, n, n, "Q" ) ); # and quit|
!gapprompt@gap>| !gapinput@BrowseProfile();|
!gapprompt@gap>| !gapinput@BrowseData.SetReplay( false );|
\end{Verbatim}
\emph{Implementation remarks}: The browse table has a dynamic header, which shows the current values of \mbox{\texttt{\mdseries\slshape mincount}} and \mbox{\texttt{\mdseries\slshape mintime}}, and a dynamic footer, which shows the sums of counts and timings for the
rows in the table (label \texttt{TOTAL}) and if applicable the sums for the profiled functions not shown in the table
(label \texttt{OTHER}). There are no row labels, and the obvious column labels. There is no return
value.
The standard modes in \texttt{BrowseData} (\ref{BrowseData}) (except the \texttt{help} mode) have been modified by adding a new action for changing the threshold
parameters \mbox{\texttt{\mdseries\slshape mincount}} and \mbox{\texttt{\mdseries\slshape mintime}} (user input \textsc{e}). The way how this in implemented made it necessary to change the standard ``reset'' action (user input \textsc{!}) of the table; note that resetting (a sorting or filtering of) the table must
not make those rows visible that shall be hidden because of the threshold
parameters.
The code can be found in the file \texttt{app/profile.g} of the package. }
}
\section{\textcolor{Chapter }{Variables defined in \textsf{GAP} packages{\textendash}a Variant}}\label{sec:pkgvardisp}
\logpage{[ 6, 9, 0 ]}
\hyperdef{L}{X87B30F7387C0E531}{}
{
A \textsf{Browse} adapted way to list the variables that are defined in a \textsf{GAP} package is to show the overview that is printed by the \textsf{GAP} function \texttt{ShowPackageVariables} (\textbf{Reference: ShowPackageVariables}) in a \textsf{Browse} table.
\subsection{\textcolor{Chapter }{BrowsePackageVariables}}
\logpage{[ 6, 9, 1 ]}\nobreak
\hyperdef{L}{X8030B1688335783D}{}
{\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{BrowsePackageVariables({\mdseries\slshape pkgname[, version][, arec]})\index{BrowsePackageVariables@\texttt{BrowsePackageVariables}}
\label{BrowsePackageVariables}
}\hfill{\scriptsize (function)}}\\
\textbf{\indent Returns:\ }
nothing.
The arguments can be the same as for \texttt{ShowPackageVariables} (\textbf{Reference: ShowPackageVariables}), that is, \mbox{\texttt{\mdseries\slshape pkgname}} is the name of a \textsf{GAP} package, and the optional arguments \mbox{\texttt{\mdseries\slshape version}} and \mbox{\texttt{\mdseries\slshape arec}} are a version number of this package and a record used for customizing the
output, respectively.
Alternatively, the second argument can be the output \texttt{info} of \texttt{PackageVariablesInfo} (\textbf{Reference: PackageVariablesInfo}) for the package in question, instead of the version number.
\texttt{BrowsePackageVariables} opens a browse table that shows the global variables that become bound and the
methods that become installed when \textsf{GAP} loads the package \mbox{\texttt{\mdseries\slshape pkgname}}.
The table is categorized by the kinds of variables (new or redeclared
operations, methods, info classes, synonyms, other globals). The column ``Doc.?'' distinguishes undocumented and documented variables, so one can use this
column as a filter or for categorizing. The column ``Filename'' shows the names of the package files. Clicking a selected row of the table
opens the relevant package file at the code in question.
The idea behind the argument \texttt{info} is that using the same arguments as for \texttt{ShowPackageVariables} (\textbf{Reference: ShowPackageVariables}) does not allow one to apply \texttt{BrowsePackageVariables} to packages that have been loaded before the \textsf{Browse} package. Thus one can compute the underlying data \texttt{info} first, using \texttt{PackageVariablesInfo} (\textbf{Reference: PackageVariablesInfo}), then load the \textsf{Browse} package, and finally call \texttt{BrowsePackageVariables}.
For example, the overview of package variables for \textsf{Browse} can be shown by starting \textsf{GAP} without packages and then entering the following lines.
\begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=Example]
!gapprompt@gap>| !gapinput@pkgname:= "Browse";;|
!gapprompt@gap>| !gapinput@info:= PackageVariablesInfo( pkgname, "" );;|
!gapprompt@gap>| !gapinput@LoadPackage( "Browse" );;|
!gapprompt@gap>| !gapinput@BrowsePackageVariables( pkgname, info );|
\end{Verbatim}
If the arguments are the same as for \texttt{ShowPackageVariables} (\textbf{Reference: ShowPackageVariables}) then this function is actually called, with the consequence that the package
gets loaded when \texttt{BrowsePackageVariables} is called. This is not the case if the output of \texttt{PackageVariablesInfo} (\textbf{Reference: PackageVariablesInfo}) is entered as the second argument. }
}
\section{\textcolor{Chapter }{Configuring User preferences{\textendash}a Variant}}\label{sec:userpref}
\logpage{[ 6, 10, 0 ]}
\hyperdef{L}{X7CD025147D528741}{}
{
A \textsf{Browse} adapted way to show and edit \textsf{GAP}'s user preferences is to show the overview that is printed by the \textsf{GAP} function \texttt{ShowUserPreferences} (\textbf{Reference: ShowUserPreferences}) in a \textsf{Browse} table.
\subsection{\textcolor{Chapter }{BrowseUserPreferences}}
\logpage{[ 6, 10, 1 ]}\nobreak
\hyperdef{L}{X7A7B712E7A06449F}{}
{\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{BrowseUserPreferences({\mdseries\slshape package1, package2, ...})\index{BrowseUserPreferences@\texttt{BrowseUserPreferences}}
\label{BrowseUserPreferences}
}\hfill{\scriptsize (function)}}\\
\textbf{\indent Returns:\ }
nothing.
The arguments are the same as for \texttt{ShowUserPreferences} (\textbf{Reference: ShowUserPreferences}), that is, calling the function with no argument yields an overview of all
known user preferences, and if one or more strings \mbox{\texttt{\mdseries\slshape package1}}, $\ldots$ are given then only the user preferences for these packages are shown.
\texttt{BrowseUserPreferences} opens a browse table with the following columns:
\begin{description}
\item[{``Package''}] contains the names of the \textsf{GAP} packages to which the user preferences belong,
\item[{``Pref. names''}] contains the names of the user preferences, and
\item[{``Description''}] contains the \texttt{description} texts from the \texttt{DeclareUserPreference} (\textbf{Reference: DeclareUserPreference}) calls and the default values (if applicable), and the actual values.
\end{description}
When one ``clicks'' on one of the table rows or entries then the values of the user preference in
question can be edited. If a list of admissible values is known then this
means that one can choose from this list via \texttt{NCurses.Select} (\ref{NCurses.Select}), otherwise one can enter the desired value as text.
The values of the user preferences are not changed before one closes the
browse table. When the table is left and if one has changed at least one
value, one is asked whether the changes shall be applied.
\begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=Example]
!gapprompt@gap>| !gapinput@d:= [ NCurses.keys.DOWN ];; |
!gapprompt@gap>| !gapinput@c:= [ NCurses.keys.ENTER ];; |
!gapprompt@gap>| !gapinput@BrowseData.SetReplay( Concatenation(|
!gapprompt@>| !gapinput@ "/PackagesToLoad", # enter a search string,|
!gapprompt@>| !gapinput@ c, # start the search,|
!gapprompt@>| !gapinput@ c, # edit the entry (a list of choices),|
!gapprompt@>| !gapinput@ " ", d, # toggle the first four values,|
!gapprompt@>| !gapinput@ " ", d, #|
!gapprompt@>| !gapinput@ " ", d, #|
!gapprompt@>| !gapinput@ " ", d, #|
!gapprompt@>| !gapinput@ c, # submit the values,|
!gapprompt@>| !gapinput@ "Q", # quit the table,|
!gapprompt@>| !gapinput@ c ) ); # choose "cancel": do not apply the changes.|
!gapprompt@gap>| !gapinput@BrowseUserPreferences();|
!gapprompt@gap>| !gapinput@BrowseData.SetReplay( false );|
\end{Verbatim}
The code can be found in the file \texttt{app/userpref.g} of the package. }
}
\section{\textcolor{Chapter }{Overview of \textsf{GAP} Data}}\label{sec:datadisp}
\logpage{[ 6, 11, 0 ]}
\hyperdef{L}{X86C730A07855238D}{}
{
The \textsf{GAP} system contains several data collections such as libraries of groups and
character tables. Clearly the function \texttt{NCurses.BrowseGeneric} (\ref{NCurses.BrowseGeneric}) can be used to visualize interesting information about such data collections,
in the form of an ``overview table'' whose rows correspond to the objects in the collection; each column of the
table shows a piece of information about the objects. (One possibility to
create such overviews is given by \texttt{BrowseTableFromDatabaseIdEnumerator} (\ref{BrowseTableFromDatabaseIdEnumerator}).)
\subsection{\textcolor{Chapter }{BrowseGapData}}
\logpage{[ 6, 11, 1 ]}\nobreak
\hyperdef{L}{X850C786C87A4877B}{}
{\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{BrowseGapData({\mdseries\slshape })\index{BrowseGapData@\texttt{BrowseGapData}}
\label{BrowseGapData}
}\hfill{\scriptsize (function)}}\\
\textbf{\indent Returns:\ }
the return value of the chosen application if there is one.
The function \texttt{BrowseGapData} shows the choices in the list \texttt{BrowseData.GapDataOverviews}, in a browse table with one column. When an entry is ``clicked'' then the associated function is called, and the table of choices is closed.
The idea is that each entry of \texttt{BrowseData.GapDataOverviews} describes an overview of a data collection.
The \textsf{Browse} package provides overviews of
\begin{itemize}
\item the current AMS Mathematics Subject Classification codes (see \texttt{BrowseMSC} (\ref{BrowseMSC})),
\item the contents of the \textsf{AtlasRep} package \cite{AtlasRep} (only if this package is loaded, see Section{\nobreakspace}\ref{sec:atlasdisp}),
\item \index{BrowseConwayPolynomials@\texttt{BrowseConwayPolynomials}!see BrowseGapData} the Conway polynomials in \textsf{GAP} (calls \texttt{BrowseConwayPolynomials()}),
\item profile information for \textsf{GAP} functions (see Section{\nobreakspace}\ref{sec:profiledisp}),
\item the list of \textsf{GAP} related bibliography entries in the file \texttt{bibl/gap-publishednicer.bib} of the \textsf{Browse} package (see Section{\nobreakspace}\ref{sec:gapbibl}),
\item the \textsf{GAP} manuals (see Section{\nobreakspace}\ref{sec:manualdisp}),
\item \index{BrowseGapMethods@\texttt{BrowseGapMethods}!see BrowseGapData} \textsf{GAP} operations and methods (calls \texttt{BrowseGapMethods()}),
\item \index{BrowseGapPackages@\texttt{BrowseGapPackages}!see BrowseGapData} the installed \textsf{GAP} packages (calls \texttt{BrowseGapPackages()}),
\item \textsf{GAP}'s user preferences (see Section{\nobreakspace}\ref{sec:userpref}),
\item the contents of the \textsf{TomLib} package \cite{TomLib} (only if this package is loaded, see Section{\nobreakspace}\ref{sect:tomlibinfo}),
\end{itemize}
Other \textsf{GAP} packages may add more overviews, using the function \texttt{BrowseGapDataAdd} (\ref{BrowseGapDataAdd}). For example, there are overviews of
\begin{itemize}
\item the bibliographies in the \textsf{ATLAS} of Finite Groups \cite{CCN85} and in the \textsf{ATLAS} of Brauer Characters \cite{JLPW95} (see \texttt{BrowseBibliographySporadicSimple} (\textbf{AtlasRep: BrowseBibliographySporadicSimple})),
\item atomic irrationalities that occur in character tables in the \textsf{ATLAS} of Finite Groups \cite{CCN85} or the \textsf{ATLAS} of Brauer Characters \cite{JLPW95} (see Section \texttt{BrowseCommonIrrationalities} (\textbf{CTblLib: BrowseCommonIrrationalities})),
\item the differences between the versions of the character table data in the \textsf{CTblLib} package (see Section \texttt{BrowseCTblLibDifferences} (\textbf{CTblLib: BrowseCTblLibDifferences})),
\item the information in the \textsf{GAP} Character Table Library (see Section \texttt{BrowseCTblLibInfo} (\textbf{CTblLib: BrowseCTblLibInfo})),
\item an overview of minimal degrees of representations of groups from the \textsf{ATLAS} of Group Representations (see Section \texttt{BrowseMinimalDegrees} (\textbf{AtlasRep: BrowseMinimalDegrees})).
\end{itemize}
Except that always one table cell is selected, the full functionality of the
function \texttt{NCurses.BrowseGeneric} (\ref{NCurses.BrowseGeneric}) is available.
\begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=Example]
!gapprompt@gap>| !gapinput@n:= [ 14, 14, 14 ];; # ``do nothing''|
!gapprompt@gap>| !gapinput@# open the overview of Conway polynomials|
!gapprompt@gap>| !gapinput@BrowseData.SetReplay( Concatenation( "/Conway Polynomials",|
!gapprompt@>| !gapinput@ [ NCurses.keys.ENTER, NCurses.keys.ENTER ], "srdddd", n, "Q" ) );|
!gapprompt@gap>| !gapinput@BrowseGapData();;|
!gapprompt@gap>| !gapinput@# open the overview of GAP packages|
!gapprompt@gap>| !gapinput@BrowseData.SetReplay( Concatenation( "/GAP Packages",|
!gapprompt@>| !gapinput@ [ NCurses.keys.ENTER, NCurses.keys.ENTER ], "/Browse",|
!gapprompt@>| !gapinput@ [ NCurses.keys.ENTER ], "n", n, "Q" ) );|
!gapprompt@gap>| !gapinput@BrowseGapData();;|
!gapprompt@gap>| !gapinput@BrowseData.SetReplay( false );|
\end{Verbatim}
\emph{Implementation remarks}: The browse table has a static header, a dynamic footer showing the
description of the currently selected entry, no row or column labels, and
exactly one column of fixed width equal to the screen width. If the chosen
application has a return value then this is returned by \texttt{BrowseGapData}, otherwise nothing is returned. The component \texttt{work.SpecialGrid} of the browse table is used to draw a border around the list of choices and
another border around the footer. Only one mode is needed in which an entry is
selected.
The code can be found in the file \texttt{app/gapdata.g} of the package. }
\subsection{\textcolor{Chapter }{BrowseGapDataAdd}}
\logpage{[ 6, 11, 2 ]}\nobreak
\hyperdef{L}{X7FC24FCE7A0C6058}{}
{\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{BrowseGapDataAdd({\mdseries\slshape title, call[, ret], documentation})\index{BrowseGapDataAdd@\texttt{BrowseGapDataAdd}}
\label{BrowseGapDataAdd}
}\hfill{\scriptsize (function)}}\\
This function extends the list \texttt{BrowseData.GapDataOverviews} by a new entry. The list is used by \texttt{BrowseGapData} (\ref{BrowseGapData}).
\mbox{\texttt{\mdseries\slshape title}} must be a string of length at most $76$; it will be shown in the browse table that is opened by \texttt{BrowseGapData} (\ref{BrowseGapData}). \mbox{\texttt{\mdseries\slshape call}} must be a function that takes no arguments; it will be called when \mbox{\texttt{\mdseries\slshape title}} is ``clicked''. \mbox{\texttt{\mdseries\slshape ret}}, if given, must be \texttt{true} if \mbox{\texttt{\mdseries\slshape call}} has a return value and if \texttt{BrowseGapData} (\ref{BrowseGapData}) shall return this value, and \texttt{false} otherwise. \mbox{\texttt{\mdseries\slshape documentation}} must be a string that describes what happens when the function \mbox{\texttt{\mdseries\slshape call}} is called; it will be shown in the footer of the table opened by \texttt{BrowseGapData} (\ref{BrowseGapData}) when \mbox{\texttt{\mdseries\slshape title}} is selected. }
}
\section{\textcolor{Chapter }{Navigating in a Directory Tree}}\label{sec:filetree}
\logpage{[ 6, 12, 0 ]}
\hyperdef{L}{X7E3FDA927E62D963}{}
{
A natural way to visualize the contents of a directory is via a tree whose
leaves denote plain files, and the other vertices denote subdirectories. \textsf{Browse} provides a function based on \texttt{NCurses.BrowseGeneric} (\ref{NCurses.BrowseGeneric}) for displaying such trees; the leaves correspond to the data rows, and the
other vertices correspond to category rows.
\subsection{\textcolor{Chapter }{BrowseDirectory}}
\logpage{[ 6, 12, 1 ]}\nobreak
\hyperdef{L}{X859682DE8397261E}{}
{\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{BrowseDirectory({\mdseries\slshape [dir]})\index{BrowseDirectory@\texttt{BrowseDirectory}}
\label{BrowseDirectory}
}\hfill{\scriptsize (function)}}\\
\textbf{\indent Returns:\ }
a list of the ``clicked'' filenames.
If no argument is given then the contents of the current directory is shown,
see \texttt{DirectoryCurrent} (\textbf{Reference: DirectoryCurrent}). If a directory object \mbox{\texttt{\mdseries\slshape dir}} (see \texttt{Directory} (\textbf{Reference: Directory})) is given as the only argument then the contents of this directory is shown;
alternatively, \mbox{\texttt{\mdseries\slshape dir}} may also be a string which is then understood as a directory path.
The full functionality of the function \texttt{NCurses.BrowseGeneric} (\ref{NCurses.BrowseGeneric}) is available.
\begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=Example]
!gapprompt@gap>| !gapinput@n:= [ 14, 14, 14 ];; # ``do nothing''|
!gapprompt@gap>| !gapinput@BrowseData.SetReplay( Concatenation(|
!gapprompt@>| !gapinput@ "q", # leave the selection|
!gapprompt@>| !gapinput@ "X", # expand all categories|
!gapprompt@>| !gapinput@ "/filetree", [ NCurses.keys.ENTER ], # search for "filetree"|
!gapprompt@>| !gapinput@ n, "Q" ) ); # and quit|
!gapprompt@gap>| !gapinput@dir:= DirectoriesPackageLibrary( "Browse", "" )[1];;|
!gapprompt@gap>| !gapinput@if IsBound( BrowseDirectory ) then|
!gapprompt@>| !gapinput@ BrowseDirectory( dir );|
!gapprompt@>| !gapinput@ fi;|
!gapprompt@gap>| !gapinput@BrowseData.SetReplay( false );|
\end{Verbatim}
\emph{Implementation remarks}: The browse table has a static header, no footer, no row or column labels,
and exactly one data column. The category rows are precomputed,
i.{\nobreakspace}e., they do not arise from a table column. The tree structure
is visualized via a special grid that is shown in the separator column in
front of the table column; the width of this column is computed from the
largest nesting depth of files. For technical reasons, category rows
representing \emph{empty} directories are realized via ``dummy'' table rows; a special \texttt{ShowTables} function guarantees that these rows are always hidden.
When a data row or an entry in this row is selected, ``click'' adds the corresponding filename to the result list. Initially, the first row
is selected. (So if you want to search in the whole tree then you should quit
this selection by hitting the \textsc{q} key.)
The category hierarchy is computed using \texttt{DirectoryContents} (\textbf{Reference: DirectoryContents}).
This function is available only if the \textsf{GAP} package \textsf{IO} (see{\nobreakspace}\cite{IO}) is available, because the check for cycles uses the function \texttt{IO{\textunderscore}stat} (\textbf{IO: IO{\textunderscore}stat}) from this package.
The code can be found in the file \texttt{app/filetree.g} of the package. }
}
\section{\textcolor{Chapter }{A Puzzle}}\label{sec:mnpuzzle}
\logpage{[ 6, 13, 0 ]}
\hyperdef{L}{X7FAE33037D09CC4E}{}
{
\index{game!A Puzzle} We consider an $m$ by $n$ rectangle of squares numbered from $1$ to $m n - 1$, the bottom right square is left empty. The numbered squares are permuted by
successively exchanging the empty square and a neighboring square such that in
the end, the empty cell is again in the bottom right corner. \begin{center}
\begin{tabular}{|c|c|c|c|}\hline
$ 7$&
$13$&
$14$&
$ 2$\\
\hline
$ 1$&
$ 4$&
$15$&
$11$\\
\hline
$ 6$&
$ 8$&
$ 3$&
$ 9$\\
\hline
$10$&
$ 5$&
$12$&
$ $\\
\hline
\end{tabular}\\[2mm]
\end{center}
The aim of the game is to order the numbered squares via these moves.
For the case $m = n = 4$, the puzzle is (erroneously?) known under the name ``Sam Loyd's Fifteen'', see{\nobreakspace}\cite{LoydFifteenWeb} and{\nobreakspace}\cite{HistGames} for more information and references.
\subsection{\textcolor{Chapter }{BrowsePuzzle}}
\logpage{[ 6, 13, 1 ]}\nobreak
\hyperdef{L}{X7EF5FCBD7DAFFAF3}{}
{\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{BrowsePuzzle({\mdseries\slshape [m, n[, pi]]})\index{BrowsePuzzle@\texttt{BrowsePuzzle}}
\label{BrowsePuzzle}
}\hfill{\scriptsize (function)}}\\
\textbf{\indent Returns:\ }
a record describing the initial and final status of the puzzle.
This function shows the rectangle in a window.
The arguments \mbox{\texttt{\mdseries\slshape m}} and \mbox{\texttt{\mdseries\slshape n}} are the dimensions of the rectangle, the default for both values is $4$. The initial distribution of the numbers in the squares can be prescribed via
a permutation \mbox{\texttt{\mdseries\slshape pi}}, the default is a random element in the alternating group on the points $1, 2, \ldots, \mbox{\texttt{\mdseries\slshape m}} \mbox{\texttt{\mdseries\slshape n}} - 1$. (Note that the game has not always a solution.)
In any case, the empty cell is selected, and the selection can be moved to
neighboring cells via the arrow keys, or to any place in the same row or
column via a mouse click.
The return value is a record with the components \texttt{dim} (the pair \texttt{[ m, n ]}), \texttt{init} (the initial permutation), \texttt{final} (the final permutation), and \texttt{steps} (the number of transpositions that were needed).
\begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=Example]
!gapprompt@gap>| !gapinput@BrowseData.SetReplay( Concatenation(|
!gapprompt@>| !gapinput@ BrowsePuzzleSolution.steps, "Q" ) );|
!gapprompt@gap>| !gapinput@BrowsePuzzle( 4, 4, BrowsePuzzleSolution.init );;|
!gapprompt@gap>| !gapinput@BrowseData.SetReplay( false );|
\end{Verbatim}
An implementation using only mouse clicks but no key strokes is available in
the \textsf{GAP} package \textsf{XGAP} (see{\nobreakspace}\cite{XGAP}).
\emph{Implementation remarks}: The game board is implemented via a browse table, without row and column
labels, with static header, dynamic footer, and individual \texttt{minyx} function. Only one mode is needed in which one cell is selected, and besides
the standard actions for quitting the table, asking for help, and saving the
current window contents, only the four moves via the arrow keys and mouse
clicks are admissible. \index{mouse events}
Some standard \texttt{NCurses.BrowseGeneric} (\ref{NCurses.BrowseGeneric}) functionality, such as scrolling, selecting, and searching, are not available
in this application.
The code can be found in the file \texttt{app/puzzle.g} of the package. }
}
\section{\textcolor{Chapter }{Peg Solitaire}}\label{sec:solitaire}
\logpage{[ 6, 14, 0 ]}
\hyperdef{L}{X7FFF943D78A403C9}{}
{
\index{game!Peg Solitaire} \index{solitaire game} Peg solitaire is a board game for one player. The game board consists of
several holes some of which contain pegs. In each step of the game, one peg is
moved horizontally or vertically to an empty hole at distance two, by jumping
over a neighboring peg which is then removed from the board.
\begin{center}
\begin{tabular}{ccccccc}
\cline{3-5}
& & \multicolumn{1}{|c}{$\circ$} & \multicolumn{1}{|c}{$\circ$} &
\multicolumn{1}{|c|}{$\circ$} & & \\
\cline{3-5}
& & \multicolumn{1}{|c}{$\circ$} & \multicolumn{1}{|c}{$\circ$} &
\multicolumn{1}{|c|}{$\circ$} & & \\
\hline
\multicolumn{1}{|c}{$\circ$} & \multicolumn{1}{|c}{$\circ$} &
\multicolumn{1}{|c}{$\circ$} & \multicolumn{1}{|c}{$\circ$} &
\multicolumn{1}{|c}{$\circ$} & \multicolumn{1}{|c}{$\circ$} &
\multicolumn{1}{|c|}{$\circ$} \\
\hline
\multicolumn{1}{|c}{$\circ$} & \multicolumn{1}{|c}{$\circ$} &
\multicolumn{1}{|c}{$\circ$} & \multicolumn{1}{|c}{ } &
\multicolumn{1}{|c}{$\circ$} & \multicolumn{1}{|c}{$\circ$} &
\multicolumn{1}{|c|}{$\circ$} \\
\hline
\multicolumn{1}{|c}{$\circ$} & \multicolumn{1}{|c}{$\circ$} &
\multicolumn{1}{|c}{$\circ$} & \multicolumn{1}{|c}{$\circ$} &
\multicolumn{1}{|c}{$\circ$} & \multicolumn{1}{|c}{$\circ$} &
\multicolumn{1}{|c|}{$\circ$} \\
\hline
& & \multicolumn{1}{|c}{$\circ$} & \multicolumn{1}{|c}{$\circ$} &
\multicolumn{1}{|c|}{$\circ$} & & \\
\cline{3-5}
& & \multicolumn{1}{|c}{$\circ$} & \multicolumn{1}{|c}{$\circ$} &
\multicolumn{1}{|c|}{$\circ$} & & \\
\cline{3-5}
\end{tabular}
\end{center}
We consider the game that in the beginning, exactly one hole is empty, and in
the end, exactly one peg is left.
\subsection{\textcolor{Chapter }{PegSolitaire}}
\logpage{[ 6, 14, 1 ]}\nobreak
\hyperdef{L}{X82C8691380FCB674}{}
{\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{PegSolitaire({\mdseries\slshape [format][,] [nrholes][,] [twoModes]})\index{PegSolitaire@\texttt{PegSolitaire}}
\label{PegSolitaire}
}\hfill{\scriptsize (function)}}\\
This function shows the game board in a window.
If the argument \mbox{\texttt{\mdseries\slshape format}} is one of the strings \texttt{"small"} or \texttt{"large"} then small or large pegs are shown, the default is \texttt{"small"}.
Three shapes of the game board are supported, with $33$, $37$, and $45$ holes, respectively; this number can be specified via the argument \mbox{\texttt{\mdseries\slshape nrholes}}, the default is $33$. In the cases of $33$ and $45$ holes, the position of both the initial hole and the destination of the final
peg is the middle cell, whereas in the case of $37$ holes, the initial hole is in the top left position and the final peg has to
be placed in the bottom right position.
If a Boolean \mbox{\texttt{\mdseries\slshape twoModes}} is entered as an argument then it determines whether a browse table with one
or two modes is used; the default \texttt{false} yields a browse table with only one mode.
In any case, one cell of the board is selected, and the selection can be moved
to neighboring cells via the arrow keys. A peg in the selected cell jumps over
a neighboring peg to an adjacent hole via the \texttt{j} key followed by the appropriate arrow key.
\begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=Example]
!gapprompt@gap>| !gapinput@for n in [ 33, 37, 45 ] do|
!gapprompt@>| !gapinput@ BrowseData.SetReplay( Concatenation(|
!gapprompt@>| !gapinput@ PegSolitaireSolutions.( String( n ) ), "Q" ) );|
!gapprompt@>| !gapinput@ PegSolitaire( n );|
!gapprompt@>| !gapinput@ PegSolitaire( "large", n );|
!gapprompt@>| !gapinput@ PegSolitaire( n, true );|
!gapprompt@>| !gapinput@ PegSolitaire( "large", n, true );|
!gapprompt@>| !gapinput@od;|
!gapprompt@gap>| !gapinput@BrowseData.SetReplay( false );|
\end{Verbatim}
For more information such as variations of the game and references,
see{\nobreakspace}\cite{PegSolitaireWeb}. Also the solutions stored in the variable \texttt{PegSolitaireSolutions} have been taken from this web page.
\emph{Implementation remarks}: The game board is implemented via a browse table, without row and column
labels, with static header, dynamic footer, and individual \texttt{minyx} function. In fact, two implementations are provided. The first one needs only
one mode in which one cell is selected; moving the selection and jumping with
the peg in the selected cell in one of the four directions are the supported
user actions. The second implementation needs two modes, one for moving the
selection and one for jumping.
Some standard \texttt{NCurses.BrowseGeneric} (\ref{NCurses.BrowseGeneric}) functionality, such as scrolling, selecting, and searching, are not available
in this application.
The code can be found in the file \texttt{app/solitair.g} of the package. }
}
\section{\textcolor{Chapter }{Rubik's Cube}}\label{sec:rubikscube}
\logpage{[ 6, 15, 0 ]}
\hyperdef{L}{X862CB73B7E0BE170}{}
{
\index{game!Rubik's Cube} We visualize the transformations of Rubik's magic cube in a model that is
given by ``unfolding'' the faces and numbering them as follows.
\begin{center}
\begin{tabular}{cccccccccccc}
\cline{4-6}
& & & \multicolumn{1}{|c}{1} & \multicolumn{1}{c}{2} &
\multicolumn{1}{c|}{3} & & & & & & \\
& & & \multicolumn{1}{|c}{4} & \multicolumn{1}{c}{top} &
\multicolumn{1}{c|}{5} & & & & & & \\
& & & \multicolumn{1}{|c}{6} & \multicolumn{1}{c}{7} &
\multicolumn{1}{c|}{8} & & & & & & \\
\hline
\multicolumn{1}{|c}{9} & \multicolumn{1}{c}{10} &
\multicolumn{1}{c}{11} & \multicolumn{1}{|c}{17} &
\multicolumn{1}{c}{18} & \multicolumn{1}{c}{19} &
\multicolumn{1}{|c}{25} & \multicolumn{1}{c}{26} &
\multicolumn{1}{c}{27} & \multicolumn{1}{|c}{33} &
\multicolumn{1}{c}{34} & \multicolumn{1}{c|}{35} \\
\multicolumn{1}{|c}{12} & \multicolumn{1}{c}{left} &
\multicolumn{1}{c}{13} & \multicolumn{1}{|c}{20} &
\multicolumn{1}{c}{front} & \multicolumn{1}{c}{21} &
\multicolumn{1}{|c}{28} & \multicolumn{1}{c}{right} &
\multicolumn{1}{c}{29} & \multicolumn{1}{|c}{36} &
\multicolumn{1}{c}{back} & \multicolumn{1}{c|}{37} \\
\multicolumn{1}{|c}{14} & \multicolumn{1}{c}{15} &
\multicolumn{1}{c}{16} & \multicolumn{1}{|c}{22} &
\multicolumn{1}{c}{23} & \multicolumn{1}{c}{24} &
\multicolumn{1}{|c}{30} & \multicolumn{1}{c}{31} &
\multicolumn{1}{c}{32} & \multicolumn{1}{|c}{38} &
\multicolumn{1}{c}{39} & \multicolumn{1}{c|}{40} \\
\hline
& & & \multicolumn{1}{|c}{41} & \multicolumn{1}{c}{42} &
\multicolumn{1}{c|}{43} & & & & & & \\
& & & \multicolumn{1}{|c}{44} & \multicolumn{1}{c}{down} &
\multicolumn{1}{c|}{45} & & & & & & \\
& & & \multicolumn{1}{|c}{46} & \multicolumn{1}{c}{47} &
\multicolumn{1}{c|}{48} & & & & & & \\
\cline{4-6}
\end{tabular}
\end{center}
Clockwise turns of the six layers (top, left, front, right, back, and down)
are represented by the following permutations.
\begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=Example]
!gapprompt@gap>| !gapinput@cubegens := [|
!gapprompt@>| !gapinput@ ( 1, 3, 8, 6)( 2, 5, 7, 4)( 9,33,25,17)(10,34,26,18)(11,35,27,19),|
!gapprompt@>| !gapinput@ ( 9,11,16,14)(10,13,15,12)( 1,17,41,40)( 4,20,44,37)( 6,22,46,35),|
!gapprompt@>| !gapinput@ (17,19,24,22)(18,21,23,20)( 6,25,43,16)( 7,28,42,13)( 8,30,41,11),|
!gapprompt@>| !gapinput@ (25,27,32,30)(26,29,31,28)( 3,38,43,19)( 5,36,45,21)( 8,33,48,24),|
!gapprompt@>| !gapinput@ (33,35,40,38)(34,37,39,36)( 3, 9,46,32)( 2,12,47,29)( 1,14,48,27),|
!gapprompt@>| !gapinput@ (41,43,48,46)(42,45,47,44)(14,22,30,38)(15,23,31,39)(16,24,32,40)|
!gapprompt@>| !gapinput@];;|
\end{Verbatim}
\textsf{GAP} computations analyzing this permutation group have been part of the
announcements of \textsf{GAP}{\nobreakspace}3 releases. For a \textsf{GAP}{\nobreakspace}4 equivalent, see{\nobreakspace}\cite{RubiksCubeGAPWeb}. For more information and references (not \textsf{GAP} related) about Rubik's cube, see{\nobreakspace}\cite{RubiksCubeWeb}.
\subsection{\textcolor{Chapter }{BrowseRubiksCube}}
\logpage{[ 6, 15, 1 ]}\nobreak
\hyperdef{L}{X8100659E81FFE9A2}{}
{\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{BrowseRubiksCube({\mdseries\slshape [format][,] [pi]})\index{BrowseRubiksCube@\texttt{BrowseRubiksCube}}
\label{BrowseRubiksCube}
}\hfill{\scriptsize (function)}}\\
This function shows the model of the cube in a window.
If the argument \mbox{\texttt{\mdseries\slshape format}} is one of the strings \texttt{"small"} or \texttt{"large"} then small or large cells are shown, the default is \texttt{"small"}.
The argument \mbox{\texttt{\mdseries\slshape pi}} is the initial permutation of the faces, the default is a random permutation
in the cube group, see{\nobreakspace} (\textbf{Reference: Random}).
Supported user inputs are the keys \textsc{t}, \textsc{l}, \textsc{f}, \textsc{r}, \textsc{b}, and \textsc{d} for clockwise turns of the six layers, and the corresponding capital letters
for counter-clockwise turns. If the terminal supports colors, according to the
global variable \texttt{NCurses.attrs.has{\textunderscore}colors} (\ref{NCurses.attrs.hasuScorecolors}), the input \textsc{s} switches between a screen that shows only the colors of the faces and a screen
that shows the numbers; the color screen is the default.
The return value is a record with the components \texttt{inputs} (a string describing the user inputs), \texttt{init}, and \texttt{final} (the initial and final permutation of the faces, respectively). (The \texttt{inputs} component can be used for the replay feature, see the example below.)
In the following example, a word in terms of the generators is used to
initialize the browse table, and then the letters in this word are used as a
series of input steps, except that in between, the display is switched once
from colors to numbers and back.
\begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=Example]
!gapprompt@gap>| !gapinput@choice:= List( [ 1 .. 30 ], i -> Random( [ 1 .. 6 ] ) );;|
!gapprompt@gap>| !gapinput@input:= List( "tlfrbd", IntChar ){ choice };;|
!gapprompt@gap>| !gapinput@BrowseData.SetReplay( Concatenation(|
!gapprompt@>| !gapinput@ input{ [ 1 .. 20 ] },|
!gapprompt@>| !gapinput@ "s", # switch to number display|
!gapprompt@>| !gapinput@ input{ [ 21 .. 25 ] },|
!gapprompt@>| !gapinput@ "s", # switch to color display|
!gapprompt@>| !gapinput@ input{ [ 26 .. 30 ] },|
!gapprompt@>| !gapinput@ "Q" ) );; # quit the browse table|
!gapprompt@gap>| !gapinput@BrowseRubiksCube( Product( cubegens{ choice } ) );;|
!gapprompt@gap>| !gapinput@BrowseRubiksCube( "large", Product( cubegens{ choice } ) );;|
!gapprompt@gap>| !gapinput@BrowseData.SetReplay( false );|
\end{Verbatim}
\emph{Implementation remarks}: The cube is implemented via a browse table, without row and column labels,
with static header, dynamic footer, and individual \texttt{minyx} function. Only one mode is needed, and besides the standard actions for
quitting the table, asking for help, and saving the current window contents,
only the twelve moves and the switch between color and number display are
admissible.
Switching between the two display formats is implemented via a function \texttt{work.Main}, so this relies on \emph{not} caching the formatted cells in \texttt{work.main}.
Row and column separators of the browse table are whitespace of height and
width one. The separating lines are drawn using an individual \texttt{SpecialGrid} function in the browse table. Note that the relevant cells do not form a
rectangular array.
Some standard \texttt{NCurses.BrowseGeneric} (\ref{NCurses.BrowseGeneric}) functionality, such as scrolling, selecting, and searching, are not available
in this application.
The code can be found in the file \texttt{app/rubik.g} of the package. }
}
\section{\textcolor{Chapter }{Changing Sides}}\label{sec:knight}
\logpage{[ 6, 16, 0 ]}
\hyperdef{L}{X7ADD618186541123}{}
{
\index{game!Changing Sides} We consider a $5$ by $5$ board of squares filled with two types of stones, as follows. The square in
the middle is left empty.
\begin{center}
\begin{tabular}{|c|c|c|c|c|}
\hline
\rule[-6pt]{0pt}{18pt}$\times$&$\times$&$\times$&$\times$&$\times$\\
\hline
\rule[-6pt]{0pt}{18pt}$\circ$&$\times$&$\times$&$\times$&$\times$\\
\hline
\rule[-6pt]{0pt}{18pt}$\circ$&$\circ$&&$\times$&$\times$\\
\hline
\rule[-6pt]{0pt}{18pt}$\circ$&$\circ$&$\circ$&$\circ$&$\times$\\
\hline
\rule[-6pt]{0pt}{18pt}$\circ$&$\circ$&$\circ$&$\circ$&$\circ$\\
\hline
\end{tabular}
\end{center}
The aim of the game is to exchange the two types of stones via a sequence of
single steps that move one stone to the empty position on the board. Only
those moves are allowed that increase or decrease one coordinate by $2$ and increase or decrease the other by $1$; these are the allowed moves of the knight in chess.
This game has been part of the MacTutor system \cite{MacTutor}.
\subsection{\textcolor{Chapter }{BrowseChangeSides}}
\logpage{[ 6, 16, 1 ]}\nobreak
\hyperdef{L}{X7FCFC5858584F46E}{}
{\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{BrowseChangeSides({\mdseries\slshape })\index{BrowseChangeSides@\texttt{BrowseChangeSides}}
\label{BrowseChangeSides}
}\hfill{\scriptsize (function)}}\\
This function shows the game board in a window.
Each move is encoded as a sequence of three arrow keys; there are $24$ admissible inputs.
\begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=Example]
!gapprompt@gap>| !gapinput@for entry in BrowseChangeSidesSolutions do|
!gapprompt@>| !gapinput@ BrowseData.SetReplay( Concatenation( entry, "Q" ) );|
!gapprompt@>| !gapinput@ BrowseChangeSides();|
!gapprompt@>| !gapinput@od;|
!gapprompt@gap>| !gapinput@BrowseData.SetReplay( false );|
\end{Verbatim}
\emph{Implementation remarks}: The game board is implemented via a browse table, without row and column
labels, with static header, dynamic footer, and individual \texttt{minyx} function. Only one mode is needed, and besides the standard actions for
quitting the table, asking for help, and saving the current window contents,
only moves via combinations of the four arrow keys are admissible.
The separating lines are drawn using an individual \texttt{SpecialGrid} function in the browse table.
Some standard \texttt{NCurses.BrowseGeneric} (\ref{NCurses.BrowseGeneric}) functionality, such as scrolling, selecting, and searching, are not available
in this application.
The code can be found in the file \texttt{app/knight.g} of the package. }
}
\section{\textcolor{Chapter }{Sudoku}}\label{sec:sudoku}
\logpage{[ 6, 17, 0 ]}
\hyperdef{L}{X7DDE46668321B5E9}{}
{
\index{game!Sudoku} We consider a $9$ by $9$ board of squares. Some squares are initially filled with numbers from $1$ to $9$. The aim of the game is to fill the empty squares in such a way that each
row, each column, and each of the marked $3$ by $3$ subsquares contains all numbers from $1$ to $9$. A \emph{proper Sudoku game} is defined as one with a unique solution. Here is an example.
\begin{center}
\setlength{\unitlength}{1.8ex}
\begin{picture}(18,18)
\multiput(0,0)(2,0){10}{\line(0,1){18}}
\multiput(0,0)(0,2){10}{\line(1,0){18}}
\linethickness{0.3ex}
\multiput(0,0)(6,0){4}{\line(0,1){18}}
\multiput(0,0)(0,6){4}{\line(1,0){18}}
\put(13,17){\makebox(0,0){$5$}}
\put( 3,15){\makebox(0,0){$1$}}
\put( 5,15){\makebox(0,0){$5$}}
\put( 7,15){\makebox(0,0){$4$}}
\put(11,15){\makebox(0,0){$6$}}
\put(15,15){\makebox(0,0){$2$}}
\put( 1,13){\makebox(0,0){$9$}}
\put( 9,13){\makebox(0,0){$5$}}
\put(13,13){\makebox(0,0){$3$}}
\put( 1,11){\makebox(0,0){$6$}}
\put( 5,11){\makebox(0,0){$4$}}
\put( 7, 9){\makebox(0,0){$8$}}
\put( 1, 7){\makebox(0,0){$8$}}
\put( 7, 7){\makebox(0,0){$9$}}
\put(15, 7){\makebox(0,0){$5$}}
\put(17, 7){\makebox(0,0){$3$}}
\put(11, 5){\makebox(0,0){$5$}}
\put( 3, 3){\makebox(0,0){$4$}}
\put(11, 3){\makebox(0,0){$7$}}
\put(17, 3){\makebox(0,0){$2$}}
\put( 5, 1){\makebox(0,0){$9$}}
\put( 7, 1){\makebox(0,0){$1$}}
\put(13, 1){\makebox(0,0){$8$}}
\end{picture}
\end{center}
The \textsf{Browse} package contains functions to create, play and solve these games. There are
basic command line functions for this, which we describe first, and there is a
user interface \texttt{PlaySudoku} (\ref{PlaySudoku}) which is implemented using the generic browse functionality described in
Chapter \ref{chap:browse-user}.
\subsection{\textcolor{Chapter }{Sudoku.Init}}
\logpage{[ 6, 17, 1 ]}\nobreak
\hyperdef{L}{X789D3D4C818F4BC2}{}
{\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{Sudoku.Init({\mdseries\slshape [arg]})\index{Sudoku.Init@\texttt{Sudoku.Init}}
\label{Sudoku.Init}
}\hfill{\scriptsize (function)}}\\
\textbf{\indent Returns:\ }
A record describing a Sudoku board or \texttt{fail}.
This function constructs a record describing a Sudoku game. This is used by
the other functions described below. There a several possibilities for the
argument \mbox{\texttt{\mdseries\slshape arg}}.
\begin{description}
\item[{\mbox{\texttt{\mdseries\slshape arg}} is a string}] The entries of a Sudoku board are numbered row-wise from 1 to 81. A board is
encoded as a string as follows. If one of the numbers 1 to 9 is in entry $i$ then the corresponding digit character is written in position $i$ of the string. If an entry is empty any character, except \texttt{'1'} to \texttt{'9'} or \texttt{'|'} is written in position $i$ of the string. Trailing empty entries can be left out. Afterwards \texttt{'|'}-characters can be inserted in the string (for example to mark line ends).
Such strings can be used for \mbox{\texttt{\mdseries\slshape arg}}.
\item[{\mbox{\texttt{\mdseries\slshape arg}} is a matrix}] A Sudoku board can also be encoded as a 9 by 9-matrix, that is a list of 9
lists of length 9, whose (i,j)-th entry is the (i,j)-th entry of the board as
integer if it is not empty. Empty entries of the board correspond to unbound
entries in the matrix.
\item[{\mbox{\texttt{\mdseries\slshape arg}} is a list of integers}] Instead of the matrix just described the argument can also be given by the
concatenation of the rows of the matrix (so, a list of integers and holes).
\end{description}
\begin{Verbatim}[commandchars=!@A,fontsize=\small,frame=single,label=Example]
!gapprompt@gap>A !gapinput@game := Sudoku.Init(" 3 68 | 85 1 69| 97 53| 79 |\A
!gapprompt@>A !gapinput@ 6 47 |45 2 |89 2 1 | 4 8 7 | ");;A
\end{Verbatim}
}
\subsection{\textcolor{Chapter }{Sudoku.Place}}
\logpage{[ 6, 17, 2 ]}\nobreak
\hyperdef{L}{X86A5C6CE79DD67EE}{}
{\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{Sudoku.Place({\mdseries\slshape game, i, n})\index{Sudoku.Place@\texttt{Sudoku.Place}}
\label{Sudoku.Place}
}\hfill{\scriptsize (function)}}\\
\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{Sudoku.Remove({\mdseries\slshape game, i})\index{Sudoku.Remove@\texttt{Sudoku.Remove}}
\label{Sudoku.Remove}
}\hfill{\scriptsize (function)}}\\
\textbf{\indent Returns:\ }
The changed \mbox{\texttt{\mdseries\slshape game}}.
Here \mbox{\texttt{\mdseries\slshape game}} is a record describing a Sudoku board, as returned by \texttt{Sudoku.Init} (\ref{Sudoku.Init}). The argument \mbox{\texttt{\mdseries\slshape i}} is the number of an entry, counted row-wise from 1 to 81, and \mbox{\texttt{\mdseries\slshape n}} is an integer from 1 to 9 to be placed on the board. These functions change \mbox{\texttt{\mdseries\slshape game}}.
\texttt{Sudoku.Place} tries to place number \mbox{\texttt{\mdseries\slshape n}} on entry \mbox{\texttt{\mdseries\slshape i}}. It is an error if entry \mbox{\texttt{\mdseries\slshape i}} is not empty. The number is not placed if \mbox{\texttt{\mdseries\slshape n}} is already used in the row, column or subsquare of entry \mbox{\texttt{\mdseries\slshape i}}. In this case the component \texttt{game.impossible} is bound.
\texttt{Sudoku.Remove} tries to remove the number placed on position \mbox{\texttt{\mdseries\slshape i}} of the board. It does not change the board if entry \mbox{\texttt{\mdseries\slshape i}} is empty, or if entry \mbox{\texttt{\mdseries\slshape i}} was given when the board \mbox{\texttt{\mdseries\slshape game}} was created. In the latter case \texttt{game.impossible} is bound.
\begin{Verbatim}[commandchars=!@A,fontsize=\small,frame=single,label=Example]
!gapprompt@gap>A !gapinput@game := Sudoku.Init(" 3 68 | 85 1 69| 97 53| 79 |\A
!gapprompt@>A !gapinput@ 6 47 |45 2 |89 2 1 | 4 8 7 | ");;A
!gapprompt@gap>A !gapinput@Sudoku.Place(game, 1, 3);; # 3 is already in first rowA
!gapprompt@gap>A !gapinput@IsBound(game.impossible);A
true
!gapprompt@gap>A !gapinput@Sudoku.Place(game, 1, 2);; # 2 is not in row, col or subsquareA
!gapprompt@gap>A !gapinput@IsBound(game.impossible);A
false
\end{Verbatim}
}
\subsection{\textcolor{Chapter }{Sudoku.RandomGame}}
\logpage{[ 6, 17, 3 ]}\nobreak
\hyperdef{L}{X8401B31A879F9F9F}{}
{\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{Sudoku.RandomGame({\mdseries\slshape [seed]})\index{Sudoku.RandomGame@\texttt{Sudoku.RandomGame}}
\label{Sudoku.RandomGame}
}\hfill{\scriptsize (function)}}\\
\textbf{\indent Returns:\ }
A pair \texttt{[str, seed]} of string and seed.
The optional argument \mbox{\texttt{\mdseries\slshape seed}}, if given, must be an integer. If not given some random integer from the
current \textsf{GAP} session is used. This function returns a random proper Sudoku game, where the
board is described by a string \texttt{str}, as explained in \texttt{Sudoku.Init} (\ref{Sudoku.Init}). With the same \mbox{\texttt{\mdseries\slshape seed}} the same board is returned.
The games computed by this function have the property that after removing any
given entry the puzzle does no longer have a unique solution.
\begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=Example]
!gapprompt@gap>| !gapinput@Sudoku.RandomGame(5833750);|
[ " 1 2 43 2 68 72 8 6 2 1 9 8 8 3 9 \
47 3 7 18 ", 5833750 ]
!gapprompt@gap>| !gapinput@last = Sudoku.RandomGame(last[2]);|
true
\end{Verbatim}
}
\subsection{\textcolor{Chapter }{Sudoku.SimpleDisplay}}
\logpage{[ 6, 17, 4 ]}\nobreak
\hyperdef{L}{X86917AC57C25A68F}{}
{\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{Sudoku.SimpleDisplay({\mdseries\slshape game})\index{Sudoku.SimpleDisplay@\texttt{Sudoku.SimpleDisplay}}
\label{Sudoku.SimpleDisplay}
}\hfill{\scriptsize (function)}}\\
Displays a Sudoku board on the terminal. (But see \texttt{PlaySudoku} (\ref{PlaySudoku}) for a fancier interface.)
\begin{Verbatim}[commandchars=!@A,fontsize=\small,frame=single,label=Example]
!gapprompt@gap>A !gapinput@game := Sudoku.Init(" 3 68 | 85 1 69| 97 53| 79 |\A
!gapprompt@>A !gapinput@ 6 47 |45 2 |89 2 1 | 4 8 7 | ");;A
!gapprompt@gap>A !gapinput@Sudoku.SimpleDisplay(game);A
3 | 6|8
85| 1| 69
9|7 | 53
-----------
| |79
6 | 47|
45 | 2 |
-----------
89 | 2| 1
4 | 8| 7
| |
\end{Verbatim}
}
\subsection{\textcolor{Chapter }{Sudoku.DisplayString}}
\logpage{[ 6, 17, 5 ]}\nobreak
\hyperdef{L}{X81F98C6C7C8415AB}{}
{\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{Sudoku.DisplayString({\mdseries\slshape game})\index{Sudoku.DisplayString@\texttt{Sudoku.DisplayString}}
\label{Sudoku.DisplayString}
}\hfill{\scriptsize (function)}}\\
The string returned by this function can be used to display the Sudoku board \mbox{\texttt{\mdseries\slshape game}} on the terminal, using \texttt{PrintFormattedString} (\textbf{GAPDoc: PrintFormattedString}). The result depends on the value of \texttt{GAPInfo.TermEncoding}.
\begin{Verbatim}[commandchars=!@A,fontsize=\small,frame=single,label=Example]
!gapprompt@gap>A !gapinput@game := Sudoku.Init(" 3 68 | 85 1 69| 97 53| 79 |\A
!gapprompt@>A !gapinput@ 6 47 |45 2 |89 2 1 | 4 8 7 | ");;A
!gapprompt@gap>A !gapinput@str:= Sudoku.DisplayString( game );;A
!gapprompt@gap>A !gapinput@PrintFormattedString( str );A
+===+===+===+===+===+===+===+===+===+
| | 3 | | | | 6 | 8 | | |
+---+---+---+---+---+---+---+---+---+
| | 8 | 5 | | | 1 | | 6 | 9 |
+---+---+---+---+---+---+---+---+---+
| | | 9 | 7 | | | | 5 | 3 |
+===+===+===+===+===+===+===+===+===+
| | | | | | | 7 | 9 | |
+---+---+---+---+---+---+---+---+---+
| | 6 | | | 4 | 7 | | | |
+---+---+---+---+---+---+---+---+---+
| 4 | 5 | | | 2 | | | | |
+===+===+===+===+===+===+===+===+===+
| 8 | 9 | | | | 2 | | 1 | |
+---+---+---+---+---+---+---+---+---+
| | 4 | | | | 8 | | 7 | |
+---+---+---+---+---+---+---+---+---+
| | | | | | | | | |
+===+===+===+===+===+===+===+===+===+
\end{Verbatim}
}
\subsection{\textcolor{Chapter }{Sudoku.OneSolution}}
\logpage{[ 6, 17, 6 ]}\nobreak
\hyperdef{L}{X7C73C6D08293B3B8}{}
{\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{Sudoku.OneSolution({\mdseries\slshape game})\index{Sudoku.OneSolution@\texttt{Sudoku.OneSolution}}
\label{Sudoku.OneSolution}
}\hfill{\scriptsize (function)}}\\
\textbf{\indent Returns:\ }
A completed Sudoku board that solves \mbox{\texttt{\mdseries\slshape game}}, or \texttt{fail}.
Here \mbox{\texttt{\mdseries\slshape game}} must be a Sudoku board as returned by \texttt{Sudoku.Init} (\ref{Sudoku.Init}). It is not necessary that \mbox{\texttt{\mdseries\slshape game}} describes a proper Sudoku game (has a unique solution). It may have several
solutions, then one random solution is returned. Or it may have no solution,
then \texttt{fail} is returned.
\begin{Verbatim}[commandchars=!@A,fontsize=\small,frame=single,label=Example]
!gapprompt@gap>A !gapinput@Sudoku.SimpleDisplay(Sudoku.OneSolution(Sudoku.Init(" 3")));A
493|876|251
861|542|739
527|193|648
-----------
942|618|573
156|739|482
738|425|916
-----------
289|354|167
375|961|824
614|287|395
\end{Verbatim}
}
\subsection{\textcolor{Chapter }{Sudoku.UniqueSolution}}
\logpage{[ 6, 17, 7 ]}\nobreak
\hyperdef{L}{X865DDBDC7E16217F}{}
{\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{Sudoku.UniqueSolution({\mdseries\slshape game})\index{Sudoku.UniqueSolution@\texttt{Sudoku.UniqueSolution}}
\label{Sudoku.UniqueSolution}
}\hfill{\scriptsize (function)}}\\
\textbf{\indent Returns:\ }
A completed Sudoku board that solves \mbox{\texttt{\mdseries\slshape game}}, or \texttt{false}, or \texttt{fail}.
Here \mbox{\texttt{\mdseries\slshape game}} must be a Sudoku board as returned by \texttt{Sudoku.Init} (\ref{Sudoku.Init}). It is not necessary that \mbox{\texttt{\mdseries\slshape game}} describes a proper Sudoku game. If it has several solutions, then \texttt{false} is returned. If it has no solution, then \texttt{fail} is returned. Otherwise a board with the unique solution is returned.
\begin{Verbatim}[commandchars=!@A,fontsize=\small,frame=single,label=Example]
!gapprompt@gap>A !gapinput@s := " 5 | 154 6 2 |9 5 3 |6 4 | 8 |8 9 53\A
!gapprompt@>A !gapinput@| 5 | 4 7 2| 91 8 ";;A
!gapprompt@gap>A !gapinput@sol := Sudoku.UniqueSolution(Sudoku.Init(s));;A
!gapprompt@gap>A !gapinput@Sudoku.SimpleDisplay(sol);A
438|219|576
715|436|928
962|758|314
-----------
694|573|281
153|862|749
827|941|653
-----------
281|695|437
546|387|192
379|124|865
\end{Verbatim}
}
\subsection{\textcolor{Chapter }{PlaySudoku}}
\logpage{[ 6, 17, 8 ]}\nobreak
\hyperdef{L}{X7D19224478E86BB4}{}
{\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{PlaySudoku({\mdseries\slshape [arg]})\index{PlaySudoku@\texttt{PlaySudoku}}
\label{PlaySudoku}
}\hfill{\scriptsize (function)}}\\
\textbf{\indent Returns:\ }
A record describing the latest status of a Sudoku board.
This function allows one to solve Sudoku puzzles interactively. There are
several possibilities for the optional argument \mbox{\texttt{\mdseries\slshape arg}}. It can either be a string, matrix or list of holes and integers as described
in \texttt{Sudoku.Init} (\ref{Sudoku.Init}), or a board as returned by \texttt{Sudoku.Init} (\ref{Sudoku.Init}). Furthermore \mbox{\texttt{\mdseries\slshape arg}} can be an integer or not be given, in that case \texttt{Sudoku.RandomGame} (\ref{Sudoku.RandomGame}) is called to produce a random game.
The usage of this function is self-explanatory, pressing the \textsc{?} key displays a help screen. Here, we mention two keys with a particular
action: Pressing the \textsc{h} key you get a hint, either an empty entry is filled or the program tells you
that there is no solution (so you must delete some entries and try others).
Pressing the \textsc{s} key the puzzle is solved by the program or it tells you that there is no or no
unique solution.
\emph{Implementation remarks}: The game board is implemented via a browse table, without row and column
labels, with static header, dynamic footer, and individual \texttt{minyx} function. Two modes are supported, with the standard actions for quitting the
table and asking for help; one cell is selected in each mode. The first mode
provides actions for moving the selected cell via arrow keys, for changing the
value in the selected cell, for getting a hint or the (unique) solution.
(Initial entries of the matrix cannot be changed via user input. They are
shown in boldface.) The second mode serves for error handling: When the user
enters an invalid number, i.{\nobreakspace}e., a number that occurs already in
the current row or column or subsquare, then the application switches to this
mode, which causes that a message is shown in the footer, and the invalid
entry is shown in red and blinking; similarly, error mode is entered if a hint
or solution does not exist.
The separating lines are drawn using an individual \texttt{SpecialGrid} function in the browse table, since they cannot be specified within the
generic browse table functions.
Some standard \texttt{NCurses.BrowseGeneric} (\ref{NCurses.BrowseGeneric}) functionality, such as scrolling, selecting, and searching, are not available
in this application.
The code can be found in the file \texttt{app/sudoku.g} of the package. }
\subsection{\textcolor{Chapter }{Sudoku.HTMLGame}}
\logpage{[ 6, 17, 9 ]}\nobreak
\hyperdef{L}{X804D66D67B908F30}{}
{\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{Sudoku.HTMLGame({\mdseries\slshape game})\index{Sudoku.HTMLGame@\texttt{Sudoku.HTMLGame}}
\label{Sudoku.HTMLGame}
}\hfill{\scriptsize (function)}}\\
\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{Sudoku.LaTeXGame({\mdseries\slshape game})\index{Sudoku.LaTeXGame@\texttt{Sudoku.LaTeXGame}}
\label{Sudoku.LaTeXGame}
}\hfill{\scriptsize (function)}}\\
\textbf{\indent Returns:\ }
A string with HTML or {\LaTeX} code, respectively.
The argument of these functions is a record describing a Sudoku game. These
functions return code for including the current status of the board into a
webpage or a {\LaTeX} document. }
}
\section{\textcolor{Chapter }{Managing simple Workflows}}\label{sec:browsewizard}
\logpage{[ 6, 18, 0 ]}
\hyperdef{L}{X78E8DF8381626623}{}
{
The idea behind the function \texttt{BrowseWizard} (\ref{BrowseWizard}) is that one wants to collect interactively information from a user, by asking
a series of questions. Default answers for these questions can be provided,
perhaps depending on the answers to earlier questions. The questions and
answers are shown in a browse table, the current question is highlighted, and
this selection is automatically moved to the next question after a valid
answer has been entered. One may move up in the table, in order to change
previous answers, but one can move down only to the first unanswered question.
When the browse table gets closed (by submitting or canceling), a record with
the collected information is returned.
\subsection{\textcolor{Chapter }{BrowseWizard}}\logpage{[ 6, 18, 1 ]}
\hyperdef{L}{X7E47FC2378C276C6}{}
{
\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{BrowseWizard({\mdseries\slshape data})\index{BrowseWizard@\texttt{BrowseWizard}}
\label{BrowseWizard}
}\hfill{\scriptsize (function)}}\\
\textbf{\indent Returns:\ }
a record.
The argument \mbox{\texttt{\mdseries\slshape data}} must be a record with the components \texttt{steps} (a list of records, each representing one step in the questionnaire) and \texttt{defaults} (a record). The component \texttt{header}, if present, must be a string that is used as a header line; the default for
it is \texttt{"BrowseWizard"}.
\texttt{BrowseWizard} opens a browse table whose rows correspond to the entries of \mbox{\texttt{\mdseries\slshape data}}\texttt{.steps}. The components of \mbox{\texttt{\mdseries\slshape data}}\texttt{.defaults} are used as default values if they are present.
Beginning with the first entry, the user is asked to enter information, one
record component per entry; this may be done by entering some text, by
choosing keys from a given list of choices, or by editing a list of tabular
data. Then one can go to the next step by hitting the \textsc{ArrowDown} key (or by entering \textsc{d}), and edit this step by hitting the \textsc{Enter} key. One can also go back to previous steps and edit them again.
Some steps may be hidden from the user, depending on the information that has
been entered for the previous steps. The hide conditions are evaluated after
each step.
An implementation of a questionnaire is given by \texttt{BrowseData.ChooseSimpleGroupQuestions}, which is used in the following example. The idea is to choose the
description of a finite simple group by entering first the type (cyclic,
alternating, classical, exceptional, or sporadic) and then the relevant
parameter values. The information is then evaluated by \texttt{BrowseData.InterpretSimpleGroupDescription}, which returns a description that fits to the return values of \texttt{IsomorphismTypeInfoFiniteSimpleGroup} (\textbf{Reference: IsomorphismTypeInfoFiniteSimpleGroup}). For example, this function identifies the group \texttt{PSL}$(4,2)$ as $A_8$.)
\begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=Example]
!gapprompt@gap>| !gapinput@d:= [ NCurses.keys.DOWN ];; r:= [ NCurses.keys.RIGHT ];;|
!gapprompt@gap>| !gapinput@c:= [ NCurses.keys.ENTER ];;|
!gapprompt@gap>| !gapinput@BrowseData.SetReplay( Concatenation(|
!gapprompt@>| !gapinput@ c, # confirm the initial message|
!gapprompt@>| !gapinput@ d, # enter the first step|
!gapprompt@>| !gapinput@ d, d, # go to the choice of classical groups|
!gapprompt@>| !gapinput@ c, # confirm this choice|
!gapprompt@>| !gapinput@ c, # enter the next step|
!gapprompt@>| !gapinput@ d, d, # go to the choice of unitary groups|
!gapprompt@>| !gapinput@ c, # confirm this choice|
!gapprompt@>| !gapinput@ c, # enter the next step|
!gapprompt@>| !gapinput@ "5", c, # enter the dimension and confirm|
!gapprompt@>| !gapinput@ c, # enter the next step|
!gapprompt@>| !gapinput@ "3", c, # enter the field size and confirm|
!gapprompt@>| !gapinput@ c ) ); # confirm all choices (closes the table)|
!gapprompt@gap>| !gapinput@res:= BrowseWizard( rec(|
!gapprompt@>| !gapinput@ steps:= BrowseData.ChooseSimpleGroupQuestions,|
!gapprompt@>| !gapinput@ defaults:= rec(),|
!gapprompt@>| !gapinput@ header:= "Choose a finite simple group" ) );;|
!gapprompt@gap>| !gapinput@BrowseData.SetReplay( false );|
!gapprompt@gap>| !gapinput@BrowseData.InterpretSimpleGroupDescription( res );|
rec( parameter := [ 4, 3 ], requestedname := "U5(3)", series := "2A",
shortname := "U5(3)" )
\end{Verbatim}
The supported components of each entry in \mbox{\texttt{\mdseries\slshape data}}\texttt{.steps} are as follows.
\begin{description}
\item[{\texttt{key}}] a string, the name of the component of the result record that gets bound for
this entry.
\item[{\texttt{description}}] a string describing what information shall be entered.
\item[{\texttt{type}}] one of \texttt{"editstring"}, \texttt{"edittable"}, \texttt{"key"}, \texttt{"keys"}, \texttt{"ok"}, \texttt{"okcancel"}, \texttt{"submitcancelcontinue"}.
\item[{\texttt{keys} (only if \texttt{type} is \texttt{"key"} or \texttt{"keys"})}] either the list of pairs \texttt{[ key, alias ]} such that the user shall choose from the list of \texttt{key} values (strings), and the \texttt{alias} values (any \textsf{GAP} object) corresponding to the chosen values are entered into the result record,
or a function that takes \mbox{\texttt{\mdseries\slshape steps}} and the current result record as its arguments and returns the desired list of
pairs.
\item[{\texttt{validation} (optional)}] a function that takes \mbox{\texttt{\mdseries\slshape steps}}, the current result record, and a result candidate for the current step as
its arguments; it returns \texttt{true} if the result candidate is valid, and a string describing the reason for the
failure otherwise.
\item[{\texttt{default} (optional)}] depending on the \texttt{type} value, the alias part(s) of the chosen key(s) or the string or the list of
data records, or alternatively a function that takes \mbox{\texttt{\mdseries\slshape steps}} and the current result record as its arguments and returns the desired value.
If the \texttt{key} component of \mbox{\texttt{\mdseries\slshape data}}\texttt{.defaults} is bound and valid (according to the \texttt{validation} function) then this value is taken as the default; otherwise, the \texttt{default} component of the entry is taken as the default.
\item[{\texttt{isVisible} (optional)}] a function that takes \mbox{\texttt{\mdseries\slshape steps}} and the current result record as its arguments and returns \texttt{true} if the step shall be visible, and \texttt{false} otherwise,
\end{description}
If the \texttt{type} value of a step is \texttt{"edittable"} then also the following components are mandatory.
\begin{description}
\item[{\texttt{list}}] the current list of records to be edited; only strings are supported as the
values of the record components.
\item[{\texttt{mapping}}] a list of pairs \texttt{[ component, label ]} such that \texttt{component} is the name of a component in the entries in \texttt{list}, and \texttt{label} is the label shown in the dialog box for editing the record.
\item[{\texttt{choices} (optional)}] a list of records which can be added to \texttt{list}.
\item[{\texttt{rectodisp}}] a function that takes a record from \texttt{list} and returns a string that is shown in the browse table.
\item[{\texttt{title}}] a string, the header line of the dialog box for editing an entry.
\end{description}
The code of \texttt{BrowseWizard}, \texttt{BrowseData.ChooseSimpleGroupQuestions}, and \texttt{BrowseData.InterpretSimpleGroupDescription} can be found in the file \texttt{app/wizard.g} of the package. }
}
\section{\textcolor{Chapter }{Utility for \textsf{GAP} Demos}}\label{sec:rldemo}
\logpage{[ 6, 19, 0 ]}
\hyperdef{L}{X7BCE1AE37EFCE91D}{}
{
This application can be used with \textsf{GAP} if the user interface has \texttt{readline} support. The purpose is to simplify the typing during a demonstration of \textsf{GAP} commands.
The file format to specify \textsf{GAP} code for a demonstration is very simple: it contains blocks of lines with \textsf{GAP} input, separated by lines starting with the sequence \texttt{\#\%}. Comments in such a file can be added to one or several lines starting with \texttt{\#\%}. Here is the content of an example file \texttt{demo.demo}:
\begin{verbatim}
#% Add comments after #% characters at the beginning of a line.
#% A comment can have several lines.
#% Here is a multi-line input block:
g := MathieuGroup(11);;
cl := ConjugacyClasses(g);
#% Calling a help page
?MathieuGroup
#% The next line contains a comment in the GAP session:
a := 12;; b := 13;; # assign two numbers
#%
a*b;
#%
\end{verbatim}
(Single \texttt{\%} in the beginning of a line will also work as separators.)
A demonstration can be loaded into a \textsf{GAP} session with the command
\subsection{\textcolor{Chapter }{LoadDemoFile}}
\logpage{[ 6, 19, 1 ]}\nobreak
\hyperdef{L}{X80F418C5835C62BA}{}
{\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{LoadDemoFile({\mdseries\slshape demoname, demofile[, singleline]})\index{LoadDemoFile@\texttt{LoadDemoFile}}
\label{LoadDemoFile}
}\hfill{\scriptsize (function)}}\\
\textbf{\indent Returns:\ }
Nothing.
This function loads a demo file in the format described above. The argument \mbox{\texttt{\mdseries\slshape demoname}} is a string containing a name for the demo, and \mbox{\texttt{\mdseries\slshape demofile}} is the file name containing the demo.
If the optional argument \mbox{\texttt{\mdseries\slshape singleline}} is given and its value is \texttt{true}, the demo behaves differently with respect to input blocks that span several
lines. By default full blocks are treated as a single input line for \texttt{readline} (maybe spanning several physical lines in the terminal). If \mbox{\texttt{\mdseries\slshape singleline}} is \texttt{true} then all input lines of a block except the last one are sent to \textsf{GAP} and are evaluated automatically before the last line of the block is
displayed.
\begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=Example]
!gapprompt@gap>| !gapinput@dirs := DirectoriesPackageLibrary("Browse");;|
!gapprompt@gap>| !gapinput@demofile := Filename(dirs, "../app/demo.demo");;|
!gapprompt@gap>| !gapinput@if IsBound(GAPInfo.UseReadline) and GAPInfo.UseReadline = true then|
!gapprompt@>| !gapinput@ LoadDemoFile("My first demo", demofile);|
!gapprompt@>| !gapinput@ LoadDemoFile("My first demo (single lines)", demofile, true);|
!gapprompt@>| !gapinput@fi;|
\end{Verbatim}
}
Many demos can be loaded at the same time. They are used with the \textsc{PageDown} and \textsc{PageUp} keys.
The \textsc{PageUp} key leads to a (Browse) menu which allows one to choose a demo to start (if
several are loaded), to stop a demo or to move to another position in the
current demo (e.g., to go back to a previous point or to skip part of a demo).
The next input block of the current demo is copied into the current input line
of the \textsf{GAP} session by pressing the \textsc{PageDown} key. This line is not yet sent to \textsf{GAP}, use the \textsc{Return} key if you want to evaluate the input. (You can also still edit the input line
before evaluation.)
So, in the simplest case a demo can be done by just pressing \textsc{PageDown} and \textsc{Return} in turns. But it is always possible to type extra input during a demo by hand
or to change the input lines from the demo file before evaluation. It is no
problem if commands are interrupted by \textsc{Ctrl-C}. During a demo you are in a normal \textsf{GAP} session, this application only saves you some typing. The input lines from the
demo are put into the history of the session as if they were typed by hand.
Try it yourself with the two demos loaded in the example. This also shows the
different behaviour between default and single line mode. }
}
\appendix
\chapter{\textcolor{Chapter }{Some Tools for Database Handling}}\label{chap:brdbattr}
\logpage{[ "A", 0, 0 ]}
\hyperdef{L}{X85D4199E82A7DFA5}{}
{
Two aims of the tools described in this appendix are
\begin{itemize}
\item speeding up selection functions such as \texttt{AllCharacterTableNames} (\textbf{CTblLib: AllCharacterTableNames}) for certain data libraries of \textsf{GAP} (with not too many entries), in the sense that users can extend the list of
attributes that are treated in a special way
\item and a programmatic extension for rendering overviews of information about the
contents of databases, using \texttt{BrowseTableFromDatabaseIdEnumerator} (\ref{BrowseTableFromDatabaseIdEnumerator}).
\end{itemize}
The \textsf{GAP} objects introduced for that are \emph{database id enumerators} (see \ref{subsect:dbidenum}) and \emph{database attributes} (see \ref{subsect:dbattr}).
Contrary to the individual interfaces to the \textsf{GAP} manuals (see Section \ref{sec:manualdisp}), the \textsf{GAP} bibliography (see Section \ref{sec:gapbibl}), and the overviews of \textsf{GAP} packages, \textsf{GAP} methods, and Conway polynomials available in \textsf{GAP} (see Section \ref{sec:datadisp}), the approach that will be described here assumes a special way to access
database entries. Thus it depends on the structure of a given database whether
the tools described here are useful, or whether an individual interface fits
better. Perhaps the example shown in Section \ref{sect:dbidenumxpl} gives an impression what is possible.
\section{\textcolor{Chapter }{\textsf{GAP} Objects for Database Handling}}\label{sect:dbobjects}
\logpage{[ "A", 1, 0 ]}
\hyperdef{L}{X7A0B84C37CB9DFA3}{}
{
\subsection{\textcolor{Chapter }{Database Id Enumerators}}\label{subsect:dbidenum}
\logpage{[ "A", 1, 1 ]}
\hyperdef{L}{X7999CF7F79ACA240}{}
{
A \emph{database id enumerator} is a record \mbox{\texttt{\mdseries\slshape r}} with at least the following components.
\begin{description}
\item[{\texttt{identifiers}}] a list of ``identifiers'' of the database entries, which provides a bijection with these entries,
\item[{\texttt{entry}}] a function that takes \mbox{\texttt{\mdseries\slshape r}} and an entry in the \texttt{identifiers} list, and returns the corresponding database entry,
\item[{\texttt{attributes}}] the record whose components are the database attribute records (see Section \ref{subsect:dbattr}) for \mbox{\texttt{\mdseries\slshape r}}; this components is automatically initialized when \mbox{\texttt{\mdseries\slshape r}} is created with \texttt{DatabaseIdEnumerator} (\ref{DatabaseIdEnumerator}); database attributes can be entered with \texttt{DatabaseAttributeAdd} (\ref{DatabaseAttributeAdd}).
\end{description}
If the \texttt{identifiers} list may change over the time (because the database is extended or corrected)
then the following components are supported. They are used by \texttt{DatabaseIdEnumeratorUpdate} (\ref{DatabaseIdEnumeratorUpdate}).
\begin{description}
\item[{\texttt{version}}] a \textsf{GAP} object that describes the version of the \texttt{identifiers} component, this can be for example a string describing the time of the last
change (this time need not coincide with the time of the last update); the
default value (useful only for the case that the \texttt{identifiers} component is never changed) is an empty string,
\item[{\texttt{update}}] a function that takes \mbox{\texttt{\mdseries\slshape r}} as its argument, replaces its \texttt{identifiers} and \texttt{version} values by up-to-date versions if necessary (for example by downloading the
data), and returns \texttt{true} or \texttt{false}, depending on whether the update process was successful or not; the default
value is \texttt{ReturnTrue} (\textbf{Reference: ReturnTrue}),
\end{description}
The following component is optional.
\begin{description}
\item[{\texttt{isSorted}}] \texttt{true} means that the \texttt{identifiers} list is sorted w.r.t. \textsf{GAP}'s ordering \texttt{\texttt{\symbol{92}}{\textless}}; the default is \texttt{false}.
\end{description}
The idea behind database id enumerator objects is that such an object defines
the set of data covered by database attributes (see Section \ref{subsect:dbattr}), it provides the mapping between identifiers and the actual entries of the
database, and it defines when precomputed data of database attributes are
outdated. }
\subsection{\textcolor{Chapter }{Database Attributes}}\label{subsect:dbattr}
\logpage{[ "A", 1, 2 ]}
\hyperdef{L}{X7D2804F97EE18BA5}{}
{
A \emph{database attribute} is a record \mbox{\texttt{\mdseries\slshape a}} whose components belong to the aspects of \emph{defining} the attribute, \emph{accessing} the attribute's data, \emph{computing} (and recomputing) data, \emph{storing} data on files, and \emph{checking} data. (Additional parameters used for creating browse table columns from
database attributes are described in Section \ref{subsect:attr-browse-comp}.)
The following components are \emph{defining}, except \texttt{description} they are mandatory.
\begin{description}
\item[{\texttt{idenumerator}}] the database id enumerator to which the attribute \mbox{\texttt{\mdseries\slshape a}} is related,
\item[{\texttt{identifier}}] a string that identifies \mbox{\texttt{\mdseries\slshape a}} among all database attributes for the underlying database id enumerator (this
is used by \texttt{BrowseTableFromDatabaseIdEnumerator} (\ref{BrowseTableFromDatabaseIdEnumerator}) and when the data of \mbox{\texttt{\mdseries\slshape a}} are entered with \texttt{DatabaseAttributeSetData} (\ref{DatabaseAttributeSetData}), for example when precomputed values are read from a file),
\item[{\texttt{description}}] a string that describes the attribute in human readable form (currently just
for convenience, the default is an empty string).
\end{description}
The following components are used for \emph{accessing} data. Except \texttt{type}, they are optional, but enough information must be provided in order to make
the database attribute meaningful. If an individual \texttt{attributeValue} function is available then this function decides what is needed; for the
default function \texttt{DatabaseAttributeValueDefault} (\ref{DatabaseAttributeValueDefault}), at least one of the components \texttt{name}, \texttt{data}, \texttt{datafile} must be bound (see \texttt{DatabaseAttributeValueDefault} (\ref{DatabaseAttributeValueDefault}) for the behaviour in this case).
\begin{description}
\item[{\texttt{type}}] one of the strings \texttt{"values"} or \texttt{"pairs"}; the format of the component \texttt{data} is different for these cases,
\item[{\texttt{name}}] if bound, a string that is the name of a \textsf{GAP} function such that the database attribute encodes the values of this function
for the database entries; besides the computation of attribute values on
demand (see \texttt{DatabaseAttributeValueDefault} (\ref{DatabaseAttributeValueDefault})), this component can be used by selection functions such as \texttt{OneCharacterTableName} (\textbf{CTblLib: OneCharacterTableName}) or \texttt{AllCharacterTableNames} (\textbf{CTblLib: AllCharacterTableNames}), which take \textsf{GAP} functions and prescribed return values as their arguments {\textendash}of
course these functions must then be prepared to deal with database attributes.
\item[{\texttt{data}}] if bound, the data for this attribute; if the component \texttt{type} has the value \texttt{"values"} then the value is a list, where the entry at position \mbox{\texttt{\mdseries\slshape i}}, if bound, belongs to the \mbox{\texttt{\mdseries\slshape i}}-th entry of the \texttt{identifiers} list of \texttt{idenumerator}; if \texttt{type} is \texttt{"pairs"} then the value is a record with the components \texttt{automatic} and \texttt{nonautomatic}, and the values of these components are lists such that each entry is a list
of length two whose first entry occurs in the \texttt{identifiers} list of \mbox{\texttt{\mdseries\slshape a}}\texttt{.idenumerator} and whose second entry encodes the corresponding attribute value,
\item[{\texttt{datafile}}] if bound, the absolute name of a file that contains the data for this
attribute,
\item[{\texttt{attributeValue}}] a function that takes \mbox{\texttt{\mdseries\slshape a}} and an \texttt{identifiers} entry of its \texttt{idenumerator} value, and returns the attribute value for this identifier; typically this is \emph{not} a table cell data object that can be shown in a browse table, cf. the \texttt{viewValue} component; the default is \texttt{DatabaseAttributeValueDefault} (\ref{DatabaseAttributeValueDefault}) (Note that using individual \texttt{attributeValue} functions, one can deal with database attributes independent of actually
stored data, for example without precomputed values, such that the values are
computed on demand and afterwards are cached.),
\item[{\texttt{dataDefault}}] a \textsf{GAP} object that is regarded as the attribute value for those database entries for
which \texttt{data}, \texttt{datafile}, and \texttt{name} do not provide values; the default value is an empty string \texttt{""},
\item[{\texttt{eval}}] if this component is bound, the value is assumed to be a function that takes \mbox{\texttt{\mdseries\slshape a}} and a value from its \texttt{data} component, and returns the actual attribute value; this can be useful if one
does not want to create all attribute values in advance, because this would be
space or time consuming; another possible aspect of the \texttt{eval} component is that it may be used to strip off comments that are perhaps
contained in \texttt{data} entries,
\item[{\texttt{isSorted}}] if this component is bound to \texttt{true} and if \texttt{type} is \texttt{"pairs"} then it is assumed that the two lists in the \texttt{data} record of \mbox{\texttt{\mdseries\slshape a}} are sorted w.r.t. \textsf{GAP}'s ordering \texttt{\texttt{\symbol{92}}{\textless}}; the default is \texttt{false},
\end{description}
The following optional components are needed for \emph{computing} (or recomputing) data with \texttt{DatabaseAttributeCompute} (\ref{DatabaseAttributeCompute}). This is useful mainly for databases which can change over the time.
\begin{description}
\item[{\texttt{version}}] the \textsf{GAP} object that is the \texttt{version} component of the \texttt{idenumerator} component at the time when the stored data were entered; this value is used by \texttt{DatabaseIdEnumeratorUpdate} (\ref{DatabaseIdEnumeratorUpdate}) for deciding whether the attribute values are outdated; if \mbox{\texttt{\mdseries\slshape a}}\texttt{.datafile} is bound then it is assumed that the \texttt{version} component is set when this file is read, for example in the function \texttt{DatabaseAttributeSetData} (\ref{DatabaseAttributeSetData}),
\item[{\texttt{update}}] a function that takes \mbox{\texttt{\mdseries\slshape a}} as its argument, adjusts its data components to the current values of \mbox{\texttt{\mdseries\slshape a}}\texttt{.dbidenum} if necessary, sets the \texttt{version} component to that of \mbox{\texttt{\mdseries\slshape a}}\texttt{.dbidenum}, and returns \texttt{true} or \texttt{false}, depending on whether the update process was successful or not; the default
value is \texttt{ReturnTrue} (\textbf{Reference: ReturnTrue}),
\item[{\texttt{neededAttributes}}] a list of attribute \texttt{identifier} strings such that the values of these attributes are needed in the
computations for the current one, and therefore these should be
updated/recomputed in advance; it is assumed that the \texttt{neededAttributes} components of all database attributes of \mbox{\texttt{\mdseries\slshape a}}\texttt{.idenumerator} define a partial ordering; the default is an empty list,
\item[{\texttt{prepareAttributeComputation}}] a function with argument \mbox{\texttt{\mdseries\slshape a}} that must be called before the computations for the current attribute are
started; the default value is \texttt{ReturnTrue} (\textbf{Reference: ReturnTrue}),
\item[{\texttt{cleanupAfterAttibuteComputation}}] a function with argument \mbox{\texttt{\mdseries\slshape a}} that must be called after the computations for the current attribute are
finished; the default value is \texttt{ReturnTrue} (\textbf{Reference: ReturnTrue}), and
\item[{\texttt{create}}] a function that takes a database attribute and an entry in the \texttt{identifiers} list of its database id enumerator, and returns either the entry that shall be
stored in the \texttt{data} component, as the value for the given identifier (if this value shall be
stored in the \texttt{data} component of \mbox{\texttt{\mdseries\slshape a}}) or the \texttt{dataDefault} component of \mbox{\texttt{\mdseries\slshape a}} (if this value shall \emph{not} be stored); in order to get the actual attribute value, the \texttt{eval} function of \mbox{\texttt{\mdseries\slshape a}}, if bound, must be called with the return value. This function may assume
that the \texttt{prepareAttributeComputation} function has been called in advance, and that the \texttt{cleanupAfterAttibuteComputation} function will be called later. The \texttt{create} function is \emph{not} intended to compute an individual attribute value on demand, use a \texttt{name} component for that. (A stored \texttt{name} function is used to provide a default for the \texttt{create} function; without \texttt{name} component, there is no default for \texttt{create}.)
\end{description}
The following optional component is needed for \emph{storing} data on files.
\begin{description}
\item[{\texttt{string}}] if bound, a function that takes the pair consisting of an identifier and the
return value of the \texttt{create} function for this identifier, and returns a string that represents this value
when the data are printed to a file with \texttt{DatabaseAttributeString} (\ref{DatabaseAttributeString}); the default function returns the \texttt{String} (\textbf{Reference: String}) value of the second argument.
\end{description}
The following optional component is needed for \emph{checking} stored data.
\begin{description}
\item[{\texttt{check}}] a function that takes a string that occurs in the \texttt{identifiers} list of the \texttt{idenumerator} record, and returns \texttt{true} if the attribute value stored for this string is reasonable, and something
different from \texttt{true} if an error was detected. (One could argue that these tests can be performed
also when the values are computed, but consistency checks may involve several
entries; besides that, checking may be cheaper than recomputing.)
\end{description}
}
\subsection{\textcolor{Chapter }{How to Deal with Database Id Enumerators and Database Attributes}}\label{subsect:db-how-to-use}
\logpage{[ "A", 1, 3 ]}
\hyperdef{L}{X7B3913E28493563F}{}
{
The idea is to start with a database id enumerator (see \ref{subsect:dbidenum}), constructed with \texttt{DatabaseIdEnumerator} (\ref{DatabaseIdEnumerator}), and to define database attributes for it (see \ref{subsect:dbattr}), using \texttt{DatabaseAttributeAdd} (\ref{DatabaseAttributeAdd}). The attribute values can be precomputed and stored on files, or they are
computed when the attribute gets defined, or they are computed on demand.
The function \texttt{DatabaseAttributeCompute} (\ref{DatabaseAttributeCompute}) can be used to ``refresh'' the attribute values, that is, all values or selected values can be
recomputed; this can be necessary for example when the underlying database id
enumerator gets extended.
In data files, the function \texttt{DatabaseAttributeSetData} (\ref{DatabaseAttributeSetData}) can be used to fill the \texttt{data} component of the attribute. The contents of a data file can be produced with \texttt{DatabaseAttributeString} (\ref{DatabaseAttributeString}). }
\subsection{\textcolor{Chapter }{DatabaseIdEnumerator}}
\logpage{[ "A", 1, 4 ]}\nobreak
\hyperdef{L}{X7AE32F217CF16EDF}{}
{\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{DatabaseIdEnumerator({\mdseries\slshape arec})\index{DatabaseIdEnumerator@\texttt{DatabaseIdEnumerator}}
\label{DatabaseIdEnumerator}
}\hfill{\scriptsize (function)}}\\
\textbf{\indent Returns:\ }
a shallow copy of the record \mbox{\texttt{\mdseries\slshape arec}}, extended by default values.
For a record \mbox{\texttt{\mdseries\slshape arec}}, \texttt{DatabaseIdEnumerator} checks whether the mandatory components of a database id enumerator (see
Section \ref{subsect:dbidenum}) are present, initializes the \texttt{attributes} component, sets the defaults for unbound optional components (see \ref{subsect:attr-browse-comp}), and returns the resulting record.
A special database attribute (see Section \ref{subsect:dbattr}) with \texttt{identifier} value \texttt{"self"} is constructed automatically for the returned record by \texttt{DatabaseIdEnumerator}; its \texttt{attributeValue} function simply returns its second argument (the identifier). The optional
components of this attribute are derived from components of the database id
enumerator, so these components (see \ref{subsect:attr-browse-comp}) are supported for \mbox{\texttt{\mdseries\slshape arec}}. A typical use of the \texttt{"self"} attribute is to provide the first column in browse tables constructed by \texttt{BrowseTableFromDatabaseIdEnumerator} (\ref{BrowseTableFromDatabaseIdEnumerator}). }
\subsection{\textcolor{Chapter }{DatabaseAttributeAdd}}
\logpage{[ "A", 1, 5 ]}\nobreak
\hyperdef{L}{X8573522782D939FE}{}
{\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{DatabaseAttributeAdd({\mdseries\slshape dbidenum, arec})\index{DatabaseAttributeAdd@\texttt{DatabaseAttributeAdd}}
\label{DatabaseAttributeAdd}
}\hfill{\scriptsize (function)}}\\
For a database id enumerator \mbox{\texttt{\mdseries\slshape dbidenum}} and a record \mbox{\texttt{\mdseries\slshape arec}}, \texttt{DatabaseAttributeAdd} checks whether the mandatory components of a database attribute, except \texttt{idenumerator}, are present in \mbox{\texttt{\mdseries\slshape arec}} (see Section \ref{subsect:dbattr}), sets the \texttt{idenumerator} component, and sets the defaults for unbound optional components (see \ref{subsect:attr-browse-comp}). }
\subsection{\textcolor{Chapter }{DatabaseAttributeValueDefault}}
\logpage{[ "A", 1, 6 ]}\nobreak
\hyperdef{L}{X7C8DB23E79567A60}{}
{\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{DatabaseAttributeValueDefault({\mdseries\slshape attr, id})\index{DatabaseAttributeValueDefault@\texttt{DatabaseAttributeValueDefault}}
\label{DatabaseAttributeValueDefault}
}\hfill{\scriptsize (function)}}\\
\textbf{\indent Returns:\ }
the value of the database attribute \mbox{\texttt{\mdseries\slshape attr}} at \mbox{\texttt{\mdseries\slshape id}}.
For a database attribute \mbox{\texttt{\mdseries\slshape attr}} and an entry \mbox{\texttt{\mdseries\slshape id}} of the \texttt{identifiers} list of the underlying database id enumerator, \texttt{DatabaseAttributeValueDefault} takes the \texttt{data} entry for \mbox{\texttt{\mdseries\slshape id}}, applies the \texttt{eval} function of \mbox{\texttt{\mdseries\slshape attr}} to it if available and returns the result.
So the question is how to get the \texttt{data} entry.
First, if the \texttt{data} component of \mbox{\texttt{\mdseries\slshape attr}} is not bound then the file given by the \texttt{datafile} component of \mbox{\texttt{\mdseries\slshape attr}}, if available, is read, and otherwise \texttt{DatabaseAttributeCompute} (\ref{DatabaseAttributeCompute}) is called; afterwards it is assumed that the \texttt{data} component is bound.
The further steps depend on the \texttt{type} value of \mbox{\texttt{\mdseries\slshape attr}}.
If the \texttt{type} value of \mbox{\texttt{\mdseries\slshape attr}} is \texttt{"pairs"} then the \texttt{data} entry for \mbox{\texttt{\mdseries\slshape id}} is either contained in the \texttt{automatic} or in the \texttt{nonautomatic} list of \mbox{\texttt{\mdseries\slshape attr}}\texttt{.data}, or it is given by the \texttt{dataDefault} value of \mbox{\texttt{\mdseries\slshape attr}}. (So a perhaps available \texttt{name} function is \emph{not} used to compute the value for a missing \texttt{data} entry.)
If the \texttt{type} value of \mbox{\texttt{\mdseries\slshape attr}} is \texttt{"values"} then the \texttt{data} entry for \mbox{\texttt{\mdseries\slshape id}} is computed as follows. Let $n$ be the position of \mbox{\texttt{\mdseries\slshape id}} in the \texttt{identifiers} component of the database id enumerator. If the $n$-th entry of the \texttt{data} component of \mbox{\texttt{\mdseries\slshape attr}} is bound then take it; otherwise if the \texttt{name} component is bound then apply it to \mbox{\texttt{\mdseries\slshape id}} and take the return value; otherwise take the \texttt{dataDefault} value.
If one wants to introduce a database attribute where this functionality is not
suitable then another {\textendash}more specific{\textendash} function must be
entered as the component \texttt{attributeValue} of such an attribute. }
\subsection{\textcolor{Chapter }{DatabaseIdEnumeratorUpdate}}
\logpage{[ "A", 1, 7 ]}\nobreak
\hyperdef{L}{X80A909727E3C8311}{}
{\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{DatabaseIdEnumeratorUpdate({\mdseries\slshape dbidenum})\index{DatabaseIdEnumeratorUpdate@\texttt{DatabaseIdEnumeratorUpdate}}
\label{DatabaseIdEnumeratorUpdate}
}\hfill{\scriptsize (function)}}\\
\textbf{\indent Returns:\ }
\texttt{true} or \texttt{false}.
For a database id enumerator \mbox{\texttt{\mdseries\slshape dbidenum}} (see Section \ref{subsect:dbidenum}), \texttt{DatabaseIdEnumeratorUpdate} first calls the \texttt{update} function of \mbox{\texttt{\mdseries\slshape dbidenum}}. Afterwards, the \texttt{update} components of those of its \texttt{attributes} records are called for which the \texttt{version} component differs from that of \mbox{\texttt{\mdseries\slshape dbidenum}}.
The order in which the database attributes are updates is determined by the \texttt{neededAttributes} component.
The return value is \texttt{true} if all these functions return \texttt{true}, and \texttt{false} otherwise.
When \texttt{DatabaseIdEnumeratorUpdate} has returned \texttt{true}, the data described by \mbox{\texttt{\mdseries\slshape dbidenum}} and its database attributes are consistent and up to date. }
\subsection{\textcolor{Chapter }{DatabaseAttributeCompute}}
\logpage{[ "A", 1, 8 ]}\nobreak
\hyperdef{L}{X812075CE7A01EA04}{}
{\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{DatabaseAttributeCompute({\mdseries\slshape dbidenum, attridentifier[, what]})\index{DatabaseAttributeCompute@\texttt{DatabaseAttributeCompute}}
\label{DatabaseAttributeCompute}
}\hfill{\scriptsize (function)}}\\
\textbf{\indent Returns:\ }
\texttt{true} or \texttt{false}.
This function returns \texttt{false} if \mbox{\texttt{\mdseries\slshape dbidenum}} is not a database id enumerator, or if it does not have a database attribute
with \texttt{identifier} value \mbox{\texttt{\mdseries\slshape attridentifier}}, or if this attribute does not have a \texttt{create} function.
Otherwise the \texttt{prepareAttributeComputation} function is called, the \texttt{data} entries for the database attribute are (re)computed, the \texttt{cleanupAfterAttibuteComputation} function is called, and \texttt{true} is returned.
The optional argument \mbox{\texttt{\mdseries\slshape what}} determines which values are computed. Admissible values are
\begin{description}
\item[{\texttt{"all"}}] all \texttt{identifiers} entries of \mbox{\texttt{\mdseries\slshape dbidenum}},
\item[{\texttt{"automatic"} (the default)}] the same as \texttt{"all"} if the \texttt{type} value of the database attribute is \texttt{"values"}, otherwise only the values for the \texttt{"automatic"} component are computed,
\item[{\texttt{"new"}}] stored values are not recomputed.
\end{description}
}
\subsection{\textcolor{Chapter }{DatabaseAttributeString}}
\logpage{[ "A", 1, 9 ]}\nobreak
\hyperdef{L}{X7925640478969610}{}
{\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{DatabaseAttributeString({\mdseries\slshape idenum, idenumname, attridentifier, format})\index{DatabaseAttributeString@\texttt{DatabaseAttributeString}}
\label{DatabaseAttributeString}
}\hfill{\scriptsize (function)}}\\
\textbf{\indent Returns:\ }
a string that describes the values of the attribute.
Let \mbox{\texttt{\mdseries\slshape idenum}} be a database id enumerator (see Section \ref{subsect:dbidenum}), \mbox{\texttt{\mdseries\slshape idenumname}} be a string that denotes the variable to which the enumerator is bound, \mbox{\texttt{\mdseries\slshape attridentifier}} be the name of an attribute of type \texttt{"pairs"}, and \mbox{\texttt{\mdseries\slshape format}} be one of \texttt{"GAP"}, \texttt{"JSON"}. \texttt{DatabaseAttributeString} returns a string that can be used to set the attribute values, using \texttt{DatabaseAttributeLoadData} (\ref{DatabaseAttributeLoadData}). In the \texttt{"JSON"} case, it is not checked whether the \texttt{string} function of the attribute creates valid JSON (e.g., whether the lists are
dense). }
\subsection{\textcolor{Chapter }{DatabaseAttributeLoadData}}
\logpage{[ "A", 1, 10 ]}\nobreak
\hyperdef{L}{X877B91597F4007FD}{}
{\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{DatabaseAttributeLoadData({\mdseries\slshape attr})\index{DatabaseAttributeLoadData@\texttt{DatabaseAttributeLoadData}}
\label{DatabaseAttributeLoadData}
}\hfill{\scriptsize (function)}}\\
\textbf{\indent Returns:\ }
\texttt{true} or \texttt{false}.
If the data of the attribute \mbox{\texttt{\mdseries\slshape attr}} are stored in a file then this function loads the data. The data file is
expected to be either in JSON format (which can be produced with \texttt{DatabaseAttributeString} (\ref{DatabaseAttributeString}), with fourth argument the string \texttt{"JSON"}) and have filename extension \texttt{.json}, or to contain a call to \texttt{DatabaseAttributeSetData} (\ref{DatabaseAttributeSetData}) such that reading the file with \texttt{Read} (\textbf{Reference: Read}) sets the data. }
\subsection{\textcolor{Chapter }{DatabaseAttributeSetData}}
\logpage{[ "A", 1, 11 ]}\nobreak
\hyperdef{L}{X87A8B19C82E9FF0B}{}
{\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{DatabaseAttributeSetData({\mdseries\slshape dbidenum, attridentifier, version, data})\index{DatabaseAttributeSetData@\texttt{DatabaseAttributeSetData}}
\label{DatabaseAttributeSetData}
}\hfill{\scriptsize (function)}}\\
Let \mbox{\texttt{\mdseries\slshape dbidenum}} be a database id enumerator (see Section \ref{subsect:dbidenum}), \mbox{\texttt{\mdseries\slshape attridentifier}} be a string that is the \texttt{identifier} value of a database attribute of \mbox{\texttt{\mdseries\slshape dbidenum}}, \mbox{\texttt{\mdseries\slshape data}} be the \texttt{data} list or record for the database attribute (depending on its \texttt{type} value), and \mbox{\texttt{\mdseries\slshape version}} be the corresponding \texttt{version} value.
\texttt{DatabaseAttributeSetData} sets the \texttt{data} and \texttt{version} components of the attribute. This function is called when data files are
loaded with \texttt{DatabaseAttributeLoadData} (\ref{DatabaseAttributeLoadData}). }
}
\section{\textcolor{Chapter }{Using Database Attributes for Browse Tables}}\label{sect:dbbrowse}
\logpage{[ "A", 2, 0 ]}
\hyperdef{L}{X80E9CFA17EE7817A}{}
{
\subsection{\textcolor{Chapter }{Browse Relevant Components of Database Attributes}}\label{subsect:attr-browse-comp}
\logpage{[ "A", 2, 1 ]}
\hyperdef{L}{X7A2DD7827CBBD735}{}
{
The following optional components of database id enumerators and database
attributes are used by \texttt{BrowseTableFromDatabaseIdEnumerator} (\ref{BrowseTableFromDatabaseIdEnumerator}).
\begin{description}
\item[{\texttt{viewLabel}}] if bound, a table cell data object (see \texttt{BrowseData.IsBrowseTableCellData} (\ref{BrowseData.IsBrowseTableCellData})) that gives a \emph{short} description of the attribute, which is used as the column label in browse
tables created with \texttt{BrowseTableFromDatabaseIdEnumerator} (\ref{BrowseTableFromDatabaseIdEnumerator}); the default for database attributes is the \texttt{name} component, if bound, and otherwise the \texttt{identifier} component; the default for database id enumerators is the string \texttt{"name"},
\item[{\texttt{viewValue}}] if bound, a function that takes the output of the \texttt{attributeValue} function and returns a table cell data object (see \texttt{BrowseData.IsBrowseTableCellData} (\ref{BrowseData.IsBrowseTableCellData})) that is used as the entry of the corresponding column in browse tables
created with \texttt{BrowseTableFromDatabaseIdEnumerator} (\ref{BrowseTableFromDatabaseIdEnumerator}); the default is \texttt{String} (\textbf{Reference: String}),
\item[{\texttt{viewSort}}] if bound, a comparison function that takes two database attribute values and
returns \texttt{true} if the first value is regarded as smaller than the second when the column
corresponding to the attribute in the browse table constructed by \texttt{BrowseTableFromDatabaseIdEnumerator} (\ref{BrowseTableFromDatabaseIdEnumerator}) gets sorted, and \texttt{false} otherwise; the default is \textsf{GAP}'s \texttt{\texttt{\symbol{92}}{\textless}} operation,
\item[{\texttt{sortParameters}}] if bound, a list in the same format as the last argument of \texttt{BrowseData.SetSortParameters}, which is used for the column corresponding to the attribute in the browse
table constructed by \texttt{BrowseTableFromDatabaseIdEnumerator} (\ref{BrowseTableFromDatabaseIdEnumerator}); the default is an empty list,
\item[{\texttt{widthCol}}] if bound, the width of the column in the browse table constructed by \texttt{BrowseTableFromDatabaseIdEnumerator} (\ref{BrowseTableFromDatabaseIdEnumerator}); if a column width is prescribed this way then the function stored in the \texttt{attributeValue} component must return either a list of attribute lines that fit into the
column or a plain string (which then gets formatted as required); there is no
default for this component, meaning that the column width is computed as the
maximum of the widths of the column label and of all entries in the column if
no value is bound,
\item[{\texttt{align}}] if bound, the alignment of the values in the column of the browse table
constructed by \texttt{BrowseTableFromDatabaseIdEnumerator} (\ref{BrowseTableFromDatabaseIdEnumerator}); admissible values are substrings of \texttt{"bclt"}, see \texttt{BrowseData.IsBrowseTableCellData} (\ref{BrowseData.IsBrowseTableCellData}); the default is right and vertically centered, but note that if the \texttt{viewValues} function returns a record (see \texttt{BrowseData.IsBrowseTableCellData} (\ref{BrowseData.IsBrowseTableCellData})) then the alignment prescribed by this record is preferred,
\item[{\texttt{categoryValue}}] if bound, a function that is similar to the \texttt{viewValue} component but may return a different value; for example if the column in the
browse table belongs to a property and the \texttt{viewValue} function returns something like \texttt{"+"} or \texttt{"-"}, it may be useful that the category rows show a textual description of the
property values; the default value is the \texttt{viewValue} component; if the value is a record then its \texttt{rows} component is taken for forming category rows, if the value is an attribute
line (see \texttt{NCurses.IsAttributeLine} (\ref{NCurses.IsAttributeLine})) then there is exactly this category row, and otherwise the value is regarded
as a list of attribute lines, which is either concatenated to one category row
or turned into individual category rows, depending on the \texttt{sortParameters} value.
\end{description}
}
\subsection{\textcolor{Chapter }{BrowseTableFromDatabaseIdEnumerator}}
\logpage{[ "A", 2, 2 ]}\nobreak
\hyperdef{L}{X7F25A3E586653911}{}
{\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{BrowseTableFromDatabaseIdEnumerator({\mdseries\slshape dbidenum, labelids, columnids[, header[, footer[, choice]]]})\index{BrowseTableFromDatabaseIdEnumerator@\texttt{BrowseTableFromDatabaseIdEnumerator}}
\label{BrowseTableFromDatabaseIdEnumerator}
}\hfill{\scriptsize (function)}}\\
\textbf{\indent Returns:\ }
a record that can be used as the input of \texttt{NCurses.BrowseGeneric} (\ref{NCurses.BrowseGeneric}).
For a database id enumerator \mbox{\texttt{\mdseries\slshape dbidenum}} (see Section \ref{subsect:dbidenum}) and two lists \mbox{\texttt{\mdseries\slshape labelids}} and \mbox{\texttt{\mdseries\slshape columnids}} of \texttt{identifier} values of database attributes stored in \mbox{\texttt{\mdseries\slshape dbidenum}}, \texttt{BrowseTableFromDatabaseIdEnumerator} returns a browse table (see{\nobreakspace}\texttt{BrowseData.IsBrowseTable} (\ref{BrowseData.IsBrowseTable})) whose columns are given by the values of the specified database attributes.
The columns listed in \mbox{\texttt{\mdseries\slshape labelids}} are used to provide row label columns of the browse table, the columns listed
in \mbox{\texttt{\mdseries\slshape columnids}} yield main table columns. \mbox{\texttt{\mdseries\slshape columnids}} must be nonempty.
If the optional arguments \mbox{\texttt{\mdseries\slshape header}} and \mbox{\texttt{\mdseries\slshape footer}} are given then they must be lists or functions or records that are admissible
for the \texttt{header} and \texttt{footer} components of the \texttt{work} record of the browse table, see \texttt{BrowseData.IsBrowseTable} (\ref{BrowseData.IsBrowseTable}).
The optional argument \mbox{\texttt{\mdseries\slshape choice}}, if given, must be a subset of \mbox{\texttt{\mdseries\slshape dbidenum}}\texttt{.identifiers}. The rows of the returned browse table are then restricted to this subset.
The returned browse table does not support ``Click'' events or return values. }
}
\section{\textcolor{Chapter }{Example: Database Id Enumerators and Database Attributes}}\label{sect:dbidenumxpl}
\logpage{[ "A", 3, 0 ]}
\hyperdef{L}{X808BDD24857F3904}{}
{
As an example for the functions introduced in this appendix, we introduce the \emph{database of small integers}. For that, we fix a positive integer $n$ and consider the integers from $1$ to $n$ as the entries of our database. Using these integers as their own identifiers,
we construct the database id enumerator.
\begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=Example]
!gapprompt@gap>| !gapinput@n:= 100;;|
!gapprompt@gap>| !gapinput@smallintenum1:= DatabaseIdEnumerator( rec(|
!gapprompt@>| !gapinput@ identifiers:= [ 1 .. n ],|
!gapprompt@>| !gapinput@ entry:= function( dbidenum, id ) return id; end,|
!gapprompt@>| !gapinput@ ) );;|
\end{Verbatim}
Examples of attributes for this database are the properties whether or not an
integer is a prime or a prime power. There are global \textsf{GAP} functions \texttt{IsPrimeInt} (\textbf{Reference: IsPrimeInt}) and \texttt{IsPrimePowerInt} (\textbf{Reference: IsPrimePowerInt}) for computing these properties, so we can define these database attributes via
a \texttt{name} component; we choose \texttt{"values"} as the \texttt{type} value, so the values (\texttt{true} or \texttt{false}) are stored in a list of length $n$ for each of the two database attributes.
\begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=Example]
!gapprompt@gap>| !gapinput@DatabaseAttributeAdd( smallintenum1, rec(|
!gapprompt@>| !gapinput@ identifier:= "primes",|
!gapprompt@>| !gapinput@ type:= "values",|
!gapprompt@>| !gapinput@ name:= "IsPrimeInt",|
!gapprompt@>| !gapinput@ ) );|
!gapprompt@gap>| !gapinput@DatabaseAttributeAdd( smallintenum1, rec(|
!gapprompt@>| !gapinput@ identifier:= "prime powers",|
!gapprompt@>| !gapinput@ type:= "values",|
!gapprompt@>| !gapinput@ name:= "IsPrimePowerInt",|
!gapprompt@>| !gapinput@ ) );|
\end{Verbatim}
Similarly, we consider the prime factors as a database attribute.
\begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=Example]
!gapprompt@gap>| !gapinput@DatabaseAttributeAdd( smallintenum1, rec(|
!gapprompt@>| !gapinput@ identifier:= "factors",|
!gapprompt@>| !gapinput@ type:= "values",|
!gapprompt@>| !gapinput@ name:= "Factors",|
!gapprompt@>| !gapinput@ ) );|
\end{Verbatim}
Another example of an attribute of integers is the residue modulo $11$. We do not want to introduce a global \textsf{GAP} function for computing the value, so we use the \texttt{create} component in order to define the attribute; again, the values (integers from $0$ to $10$) are stored in a list of length $n$.
\begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=Example]
!gapprompt@gap>| !gapinput@DatabaseAttributeAdd( smallintenum1, rec(|
!gapprompt@>| !gapinput@ identifier:= "residue mod 11",|
!gapprompt@>| !gapinput@ type:= "values",|
!gapprompt@>| !gapinput@ create:= function( attr, id ) return id mod 11; end,|
!gapprompt@>| !gapinput@ ) );|
\end{Verbatim}
Some integers are values of \texttt{Factorial} (\textbf{Reference: Factorial}), and we want to record this information and show it in a browse table. For
most integers, nothing is stored and shown for this attribute, so we choose
the \texttt{type} value \texttt{"pairs"} and precompute the information for the \texttt{data} component. (The default for the \texttt{dataDefault} component is an empty string, which is fine; so we need not prescribe this
component.)
\begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=Example]
!gapprompt@gap>| !gapinput@factorialdata:= function( n )|
!gapprompt@>| !gapinput@ local result, i, f;|
!gapprompt@>| !gapinput@ result:= []; i:= 1; f:= 1;;|
!gapprompt@>| !gapinput@ while f <= n do|
!gapprompt@>| !gapinput@ Add( result, [ f, i ] ); i:= i + 1; f:= f * i;|
!gapprompt@>| !gapinput@ od;|
!gapprompt@>| !gapinput@ return result;|
!gapprompt@>| !gapinput@ end;;|
!gapprompt@gap>| !gapinput@DatabaseAttributeAdd( smallintenum1, rec(|
!gapprompt@>| !gapinput@ identifier:= "inverse factorial",|
!gapprompt@>| !gapinput@ type:= "pairs",|
!gapprompt@>| !gapinput@ data:= rec( automatic:= factorialdata( n ), nonautomatic:= [] ),|
!gapprompt@>| !gapinput@ isSorted:= true,|
!gapprompt@>| !gapinput@ ) );|
\end{Verbatim}
We use this setup for creating a browse table. The integers are shown as the
first column, using the \texttt{"self"} attribute. This attribute can be used as a column of row labels (useful if we
want to keep the column visible when one scrolls the table to the right) or as
a column in the main table (useful if we want to search for the values); here
we choose the former possibility.
\begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=Example]
!gapprompt@gap>| !gapinput@t1:= BrowseTableFromDatabaseIdEnumerator( smallintenum1,|
!gapprompt@>| !gapinput@ [ "self" ],|
!gapprompt@>| !gapinput@ [ "primes", "prime powers", "factors", "residue mod 11",|
!gapprompt@>| !gapinput@ "inverse factorial" ] );;|
\end{Verbatim}
The following session shows some of the features of the browse table.
\begin{Verbatim}[commandchars=@|A,fontsize=\small,frame=single,label=Example]
@gapprompt|gap>A @gapinput|nop:= [ 14, 14, 14, 14, 14, 14 ];; # ``do nothing''A
@gapprompt|gap>A @gapinput|sample_session:= Concatenation(A
@gapprompt|>A @gapinput| # categorize by the first column, expand categories, wait, resetA
@gapprompt|>A @gapinput| nop, "scsc", nop, "X", nop, "!",A
@gapprompt|>A @gapinput| # sort the residue column, wait, resetA
@gapprompt|>A @gapinput| "scrrrso", nop, "!",A
@gapprompt|>A @gapinput| # categorize by the inverse factorial columnA
@gapprompt|>A @gapinput| "rscsrdx", nop, "!",A
@gapprompt|>A @gapinput| # and quit the applicationA
@gapprompt|>A @gapinput| "qQ" );;A
@gapprompt|gap>A @gapinput|BrowseData.SetReplay( sample_session );A
@gapprompt|gap>A @gapinput|NCurses.BrowseGeneric( t1 );A
@gapprompt|gap>A @gapinput|BrowseData.SetReplay( false );A
@gapprompt|gap>A @gapinput|Unbind( t1.dynamic.replay );A
\end{Verbatim}
(Note that the last statement above is necessary to run the session more than
once.) The result is not too bad but we can improve the table, using the
optional components of database attributes, as follows.
\begin{itemize}
\item The strings \texttt{"true"} and \texttt{"false"} shown for the Boolean valued database attributes can be replaced by the
perhaps more suggestive strings \texttt{"+"} and \texttt{"-"} (or perhaps an empty string instead of \texttt{"-"}).
\item The alignment of values inside their columns can be customized.
\item When the browse table is categorized by a column then the values in this
column do usually not provide suitable category rows; we can prescribe
individual category values.
\item The column labels can be customized.
\item Where the lexicographic order is not appropriate for sorting table entries, we
can prescribe an individual comparison function.
\item Sort parameters can be customized.
\item We can prescribe the width of a column, and thus distribute the attribute
values for this column to several rows when the values are too long.
\item Finally, in the call of \texttt{BrowseTableFromDatabaseIdEnumerator} (\ref{BrowseTableFromDatabaseIdEnumerator}), we can add a header to the browse table.
\end{itemize}
We create a new database id enumerator and the corresponding browse table, in
order to be able to compare the behaviour of the two objects. However, we
assume that the variables \texttt{n} and \texttt{factorialdata} are already available.
\begin{Verbatim}[commandchars=@|G,fontsize=\small,frame=single,label=Example]
@gapprompt|gap>G @gapinput|smallintenum2:= DatabaseIdEnumerator( rec(G
@gapprompt|>G @gapinput| identifiers:= [ 1 .. n ],G
@gapprompt|>G @gapinput| entry:= function( dbidenum, id ) return id; end,G
@gapprompt|>G @gapinput| viewLabel:= "",G
@gapprompt|>G @gapinput| ) );;G
@gapprompt|gap>G @gapinput|DatabaseAttributeAdd( smallintenum2, rec(G
@gapprompt|>G @gapinput| identifier:= "primes",G
@gapprompt|>G @gapinput| type:= "values",G
@gapprompt|>G @gapinput| name:= "IsPrimeInt",G
@gapprompt|>G @gapinput| viewLabel:= "prime?",G
@gapprompt|>G @gapinput| viewValue:= value -> BrowseData.ReplacedEntry( value,G
@gapprompt|>G @gapinput| [ true, false ], [ "+", "-" ] ),G
@gapprompt|>G @gapinput| sortParameters:= [ "add counter on categorizing", "yes" ],G
@gapprompt|>G @gapinput| align:= "c",G
@gapprompt|>G @gapinput| categoryValue:= value -> BrowseData.ReplacedEntry( value,G
@gapprompt|>G @gapinput| [ true, false ], [ "prime", "nonprime" ] ),G
@gapprompt|>G @gapinput| ) );G
@gapprompt|gap>G @gapinput|DatabaseAttributeAdd( smallintenum2, rec(G
@gapprompt|>G @gapinput| identifier:= "prime powers",G
@gapprompt|>G @gapinput| type:= "values",G
@gapprompt|>G @gapinput| name:= "IsPrimePowerInt",G
@gapprompt|>G @gapinput| viewLabel:= "prime power?",G
@gapprompt|>G @gapinput| viewValue:= value -> BrowseData.ReplacedEntry( value,G
@gapprompt|>G @gapinput| [ true, false ], [ "+", "-" ] ),G
@gapprompt|>G @gapinput| sortParameters:= [ "add counter on categorizing", "yes" ],G
@gapprompt|>G @gapinput| align:= "c",G
@gapprompt|>G @gapinput| categoryValue:= value -> BrowseData.ReplacedEntry( value,G
@gapprompt|>G @gapinput| [ true, false ], [ "prime power", "not prime power" ] ),G
@gapprompt|>G @gapinput| ) );G
@gapprompt|gap>G @gapinput|DatabaseAttributeAdd( smallintenum2, rec(G
@gapprompt|>G @gapinput| identifier:= "factors",G
@gapprompt|>G @gapinput| type:= "values",G
@gapprompt|>G @gapinput| name:= "Factors",G
@gapprompt|>G @gapinput| viewLabel:= "factors",G
@gapprompt|>G @gapinput| viewValue:= value -> JoinStringsWithSeparator( List( value, String ),G
@gapprompt|>G @gapinput| " * "),G
@gapprompt|>G @gapinput| widthCol:= 10,G
@gapprompt|>G @gapinput| ) );G
@gapprompt|gap>G @gapinput|DatabaseAttributeAdd( smallintenum2, rec(G
@gapprompt|>G @gapinput| identifier:= "residue mod 11",G
@gapprompt|>G @gapinput| type:= "values",G
@gapprompt|>G @gapinput| create:= function( attr, id ) return id mod 11; end,G
@gapprompt|>G @gapinput| viewSort:= BrowseData.SortAsIntegers,G
@gapprompt|>G @gapinput| categoryValue:= res -> Concatenation( String( res ), " mod 11" ),G
@gapprompt|>G @gapinput| ) );G
@gapprompt|gap>G @gapinput|DatabaseAttributeAdd( smallintenum2, rec(G
@gapprompt|>G @gapinput| identifier:= "inverse factorial",G
@gapprompt|>G @gapinput| type:= "pairs",G
@gapprompt|>G @gapinput| data:= rec( automatic:= factorialdata( n ), nonautomatic:= [] ),G
@gapprompt|>G @gapinput| isSorted:= true,G
@gapprompt|>G @gapinput| categoryValue:= function( k )G
@gapprompt|>G @gapinput| if k = "" thenG
@gapprompt|>G @gapinput| return "(no factorial)";G
@gapprompt|>G @gapinput| elseG
@gapprompt|>G @gapinput| return Concatenation( String( k ), "!" );G
@gapprompt|>G @gapinput| fi;G
@gapprompt|>G @gapinput| end,G
@gapprompt|>G @gapinput| ) );G
@gapprompt|gap>G @gapinput|t2:= BrowseTableFromDatabaseIdEnumerator( smallintenum2,G
@gapprompt|>G @gapinput| [ "self" ],G
@gapprompt|>G @gapinput| [ "primes", "prime powers", "factors", "residue mod 11",G
@gapprompt|>G @gapinput| "inverse factorial" ],G
@gapprompt|>G @gapinput| t -> BrowseData.HeaderWithRowCounter( t, "Small integers", n ) );;G
\end{Verbatim}
We run the same session as with the browse table for \texttt{smallintenum1}.
\begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=Example]
!gapprompt@gap>| !gapinput@BrowseData.SetReplay( sample_session );|
!gapprompt@gap>| !gapinput@NCurses.BrowseGeneric( t2 );|
!gapprompt@gap>| !gapinput@BrowseData.SetReplay( false );|
!gapprompt@gap>| !gapinput@Unbind( t2.dynamic.replay );|
\end{Verbatim}
Another possibility to change the look of the table is to combine the columns
for the two Boolean valued database attributes in one column, by showing the
string \texttt{"+"} for prime powers, as before, and showing this string in boldface red if the
number in question is a prime. We implement this idea in the following
database attribute. However, note that this can be a bad idea because text
attributes may be not supported in the user's terminal (see Section \ref{ssec:ncursesAttrs}), or the user may have difficulties to see or to distinguish colors; also, it
must be documented which information is encoded in the table, and the column
label might be not sufficient for explaining what the text attributes mean.
Alternatively, we could show for example combined symbols such as \texttt{++}, \texttt{+-}, \texttt{--} for primes, prime powers, and non-prime-powers, respectively. (We see that
besides these issues, the required \textsf{GAP} code is more involved than what is needed for the examples above.)
\begin{Verbatim}[commandchars=@|J,fontsize=\small,frame=single,label=Example]
@gapprompt|gap>J @gapinput|DatabaseAttributeAdd( smallintenum2, rec(J
@gapprompt|>J @gapinput| identifier:= "primes & prime powers",J
@gapprompt|>J @gapinput| type:= "values",J
@gapprompt|>J @gapinput| create:= function( attr, id )J
@gapprompt|>J @gapinput| if IsPrimeInt( id ) thenJ
@gapprompt|>J @gapinput| return 2;J
@gapprompt|>J @gapinput| elif IsPrimePowerInt( id ) thenJ
@gapprompt|>J @gapinput| return 1;J
@gapprompt|>J @gapinput| elseJ
@gapprompt|>J @gapinput| return 0;J
@gapprompt|>J @gapinput| fi;J
@gapprompt|>J @gapinput| end,J
@gapprompt|>J @gapinput| viewLabel:= [ NCurses.attrs.BOLD + NCurses.ColorAttr( "red", -1 ),J
@gapprompt|>J @gapinput| "prime", NCurses.attrs.NORMAL, " power?" ],J
@gapprompt|>J @gapinput| viewValue:= value -> BrowseData.ReplacedEntry( value,J
@gapprompt|>J @gapinput| [ 0, 1, 2 ], [ "-", "+",J
@gapprompt|>J @gapinput| [ NCurses.attrs.BOLD + NCurses.ColorAttr( "red", -1 ),J
@gapprompt|>J @gapinput| true, "+",J
@gapprompt|>J @gapinput| NCurses.ColorAttr( "red", -1 ), false ] ] ),J
@gapprompt|>J @gapinput| sortParameters:= [ "add counter on categorizing", "yes" ],J
@gapprompt|>J @gapinput| align:= "c",J
@gapprompt|>J @gapinput| categoryValue:= value -> BrowseData.ReplacedEntry( value,J
@gapprompt|>J @gapinput| [ 0, 1, 2 ],J
@gapprompt|>J @gapinput| [ "not prime power", "prime power, not prime", "prime" ] ),J
@gapprompt|>J @gapinput| ) );J
@gapprompt|gap>J @gapinput|t3:= BrowseTableFromDatabaseIdEnumerator( smallintenum2,J
@gapprompt|>J @gapinput| [ "self" ],J
@gapprompt|>J @gapinput| [ "primes & prime powers", "residue mod 11",J
@gapprompt|>J @gapinput| "inverse factorial" ],J
@gapprompt|>J @gapinput| t -> BrowseData.HeaderWithRowCounter( t, "Small integers", n ) );;J
@gapprompt|gap>J @gapinput|sample_session2:= Concatenation(J
@gapprompt|>J @gapinput| # categorize by the first column, expand categories, wait, resetJ
@gapprompt|>J @gapinput| nop, "scsc", nop, "X", nop, "!", "Q" );;J
@gapprompt|gap>J @gapinput|BrowseData.SetReplay( sample_session2 );J
@gapprompt|gap>J @gapinput|NCurses.BrowseGeneric( t3 );J
@gapprompt|gap>J @gapinput|BrowseData.SetReplay( false );J
@gapprompt|gap>J @gapinput|Unbind( t3.dynamic.replay );J
\end{Verbatim}
Now we want to consider the database as extendible, that is, we want to be
able to increase $n$ after constructing the database attributes. For that, we use $n$ as the \texttt{version} value of the database id enumerator, and provide \texttt{version} and \texttt{update} components for all attributes.
Again, we start the construction from scratch.
\begin{Verbatim}[commandchars=@|G,fontsize=\small,frame=single,label=Example]
@gapprompt|gap>G @gapinput|smallintenum3:= DatabaseIdEnumerator( rec(G
@gapprompt|>G @gapinput| identifiers:= [ 1 .. n ],G
@gapprompt|>G @gapinput| entry:= function( dbidenum, id ) return id; end,G
@gapprompt|>G @gapinput| viewLabel:= "",G
@gapprompt|>G @gapinput| version:= n,G
@gapprompt|>G @gapinput| update:= function( dbidenum )G
@gapprompt|>G @gapinput| dbidenum.identifiers:= [ 1 .. n ];G
@gapprompt|>G @gapinput| dbidenum.version:= n;G
@gapprompt|>G @gapinput| return true;G
@gapprompt|>G @gapinput| end,G
@gapprompt|>G @gapinput| ) );;G
@gapprompt|gap>G @gapinput|updateByUnbindData:= function( attr )G
@gapprompt|>G @gapinput| Unbind( attr.data );G
@gapprompt|>G @gapinput| return true;G
@gapprompt|>G @gapinput| end;;G
@gapprompt|gap>G @gapinput|DatabaseAttributeAdd( smallintenum3, rec(G
@gapprompt|>G @gapinput| identifier:= "primes",G
@gapprompt|>G @gapinput| type:= "values",G
@gapprompt|>G @gapinput| name:= "IsPrimeInt",G
@gapprompt|>G @gapinput| viewLabel:= "prime?",G
@gapprompt|>G @gapinput| viewValue:= value -> BrowseData.ReplacedEntry( value,G
@gapprompt|>G @gapinput| [ true, false ], [ "+", "-" ] ),G
@gapprompt|>G @gapinput| sortParameters:= [ "add counter on categorizing", "yes" ],G
@gapprompt|>G @gapinput| align:= "c",G
@gapprompt|>G @gapinput| categoryValue:= value -> BrowseData.ReplacedEntry( value,G
@gapprompt|>G @gapinput| [ true, false ], [ "prime", "nonprime" ] ),G
@gapprompt|>G @gapinput| version:= n,G
@gapprompt|>G @gapinput| update:= updateByUnbindData,G
@gapprompt|>G @gapinput| ) );G
@gapprompt|gap>G @gapinput|DatabaseAttributeAdd( smallintenum3, rec(G
@gapprompt|>G @gapinput| identifier:= "prime powers",G
@gapprompt|>G @gapinput| type:= "values",G
@gapprompt|>G @gapinput| name:= "IsPrimePowerInt",G
@gapprompt|>G @gapinput| viewLabel:= "prime power?",G
@gapprompt|>G @gapinput| viewValue:= value -> BrowseData.ReplacedEntry( value,G
@gapprompt|>G @gapinput| [ true, false ], [ "+", "-" ] ),G
@gapprompt|>G @gapinput| sortParameters:= [ "add counter on categorizing", "yes" ],G
@gapprompt|>G @gapinput| align:= "c",G
@gapprompt|>G @gapinput| categoryValue:= value -> BrowseData.ReplacedEntry( value,G
@gapprompt|>G @gapinput| [ true, false ], [ "prime power", "not prime power" ] ),G
@gapprompt|>G @gapinput| version:= n,G
@gapprompt|>G @gapinput| update:= updateByUnbindData,G
@gapprompt|>G @gapinput| ) );G
@gapprompt|gap>G @gapinput|DatabaseAttributeAdd( smallintenum3, rec(G
@gapprompt|>G @gapinput| identifier:= "factors",G
@gapprompt|>G @gapinput| type:= "values",G
@gapprompt|>G @gapinput| name:= "Factors",G
@gapprompt|>G @gapinput| viewLabel:= "factors",G
@gapprompt|>G @gapinput| viewValue:= value -> JoinStringsWithSeparator( List( value, String ),G
@gapprompt|>G @gapinput| " * "),G
@gapprompt|>G @gapinput| widthCol:= 10,G
@gapprompt|>G @gapinput| version:= n,G
@gapprompt|>G @gapinput| update:= updateByUnbindData,G
@gapprompt|>G @gapinput| ) );G
@gapprompt|gap>G @gapinput|DatabaseAttributeAdd( smallintenum3, rec(G
@gapprompt|>G @gapinput| identifier:= "residue mod 11",G
@gapprompt|>G @gapinput| type:= "values",G
@gapprompt|>G @gapinput| create:= function( attr, id ) return id mod 11; end,G
@gapprompt|>G @gapinput| viewSort:= BrowseData.SortAsIntegers,G
@gapprompt|>G @gapinput| categoryValue:= res -> Concatenation( String( res ), " mod 11" ),G
@gapprompt|>G @gapinput| version:= n,G
@gapprompt|>G @gapinput| update:= updateByUnbindData,G
@gapprompt|>G @gapinput| ) );G
@gapprompt|gap>G @gapinput|DatabaseAttributeAdd( smallintenum3, rec(G
@gapprompt|>G @gapinput| identifier:= "inverse factorial",G
@gapprompt|>G @gapinput| type:= "pairs",G
@gapprompt|>G @gapinput| data:= rec( automatic:= factorialdata( n ), nonautomatic:= [] ),G
@gapprompt|>G @gapinput| isSorted:= true,G
@gapprompt|>G @gapinput| categoryValue:= function( k )G
@gapprompt|>G @gapinput| if k = "" thenG
@gapprompt|>G @gapinput| return "(no factorial)";G
@gapprompt|>G @gapinput| elseG
@gapprompt|>G @gapinput| return Concatenation( String( k ), "!" );G
@gapprompt|>G @gapinput| fi;G
@gapprompt|>G @gapinput| end,G
@gapprompt|>G @gapinput| version:= n,G
@gapprompt|>G @gapinput| update:= function( attr )G
@gapprompt|>G @gapinput| attr.data.automatic:= factorialdata( n );G
@gapprompt|>G @gapinput| return true;G
@gapprompt|>G @gapinput| end,G
@gapprompt|>G @gapinput| ) );G
\end{Verbatim}
Now we can change the set of database entries by assigning a new value to the
variable \texttt{n}, and then calling \texttt{DatabaseIdEnumeratorUpdate} (\ref{DatabaseIdEnumeratorUpdate}).
\begin{Verbatim}[commandchars=!@|,fontsize=\small,frame=single,label=Example]
!gapprompt@gap>| !gapinput@n:= 200;;|
!gapprompt@gap>| !gapinput@DatabaseIdEnumeratorUpdate( smallintenum3 );|
true
!gapprompt@gap>| !gapinput@t4:= BrowseTableFromDatabaseIdEnumerator( smallintenum3,|
!gapprompt@>| !gapinput@ [ "self" ], [ "primes", "prime powers", "factors", "residue mod 11",|
!gapprompt@>| !gapinput@ "inverse factorial" ],|
!gapprompt@>| !gapinput@ t -> BrowseData.HeaderWithRowCounter( t, "Small integers", n ) );;|
!gapprompt@gap>| !gapinput@BrowseData.SetReplay( sample_session );|
!gapprompt@gap>| !gapinput@NCurses.BrowseGeneric( t4 );|
!gapprompt@gap>| !gapinput@BrowseData.SetReplay( false );|
!gapprompt@gap>| !gapinput@Unbind( t4.dynamic.replay );|
\end{Verbatim}
}
\section{\textcolor{Chapter }{Example: An Overview of the \textsf{GAP} Library of Tables of Marks }}\label{sect:tomlibinfo}
\logpage{[ "A", 4, 0 ]}
\hyperdef{L}{X8628EF6981A524B3}{}
{
The example shown in this section deals with \textsf{GAP}'s Library of Tables of Marks (the \textsf{TomLib} package \cite{TomLib}).
\subsection{\textcolor{Chapter }{BrowseTomLibInfo}}
\logpage{[ "A", 4, 1 ]}\nobreak
\hyperdef{L}{X844D143980A0E20D}{}
{\noindent\textcolor{FuncColor}{$\triangleright$\enspace\texttt{BrowseTomLibInfo({\mdseries\slshape })\index{BrowseTomLibInfo@\texttt{BrowseTomLibInfo}}
\label{BrowseTomLibInfo}
}\hfill{\scriptsize (function)}}\\
\textbf{\indent Returns:\ }
nothing.
This function shows the contents of the \textsf{GAP} Library of Tables of Marks (the \textsf{TomLib} package, see \cite{TomLib}) in a browse table.
The first call may take substantial time (about $40$ seconds), because the data files of the \textsf{TomLib} package are evaluated. This could be improved by precomputing and caching the
values. Another possibility would be to call \texttt{BrowseTomLibInfo} once before creating a \textsf{GAP} workspace. The subsequent calls are not expensive.
The table rows correspond to the tables of marks, one column of row labels
shows the identifier of the table. The columns of the table contain
information about the group order, the number of conjugacy classes of
subgroups, the identifiers of tables of marks with fusions to and from the
given table, and the name of the file that contains the table of marks data.
The full functionality of the function \texttt{NCurses.BrowseGeneric} (\ref{NCurses.BrowseGeneric}) is available.
\begin{Verbatim}[commandchars=@|F,fontsize=\small,frame=single,label=Example]
@gapprompt|gap>F @gapinput|c:= [ NCurses.keys.ENTER ];;F
@gapprompt|gap>F @gapinput|n:= [ 14, 14, 14 ];; # ``do nothing''F
@gapprompt|gap>F @gapinput|BrowseData.SetReplay( Concatenation(F
@gapprompt|>F @gapinput| "scrrsc", # categorize the list by source tables of fusions,F
@gapprompt|>F @gapinput| "srdd", # choose a source table,F
@gapprompt|>F @gapinput| "x", # expand the list of targets of fusionsF
@gapprompt|>F @gapinput| n,F
@gapprompt|>F @gapinput| "!", # revert the categorizationF
@gapprompt|>F @gapinput| "q", # leave the mode in which a row is selectedF
@gapprompt|>F @gapinput| "scrrrrsc", # categorize the list by filenamesF
@gapprompt|>F @gapinput| "X", # expand all categoriesF
@gapprompt|>F @gapinput| n,F
@gapprompt|>F @gapinput| "!", # revert the categorizationF
@gapprompt|>F @gapinput| "scso", # sort the list by group orderF
@gapprompt|>F @gapinput| n,F
@gapprompt|>F @gapinput| "!q", # revert the sorting and selectionF
@gapprompt|>F @gapinput| "?", # open the help windowF
@gapprompt|>F @gapinput| n,F
@gapprompt|>F @gapinput| "Q", # close the help windowF
@gapprompt|>F @gapinput| "/A5", c, # search for the first occurrence of "A5"F
@gapprompt|>F @gapinput| n,F
@gapprompt|>F @gapinput| "Q" ) );; # and quit the browse tableF
@gapprompt|gap>F @gapinput|BrowseTomLibInfo();F
@gapprompt|gap>F @gapinput|BrowseData.SetReplay( false );F
\end{Verbatim}
}
}
}
\def\bibname{References\logpage{[ "Bib", 0, 0 ]}
\hyperdef{L}{X7A6F98FD85F02BFE}{}
}
\bibliographystyle{alpha}
\bibliography{browsebib.xml,manualbib.xml}
\addcontentsline{toc}{chapter}{References}
\def\indexname{Index\logpage{[ "Ind", 0, 0 ]}
\hyperdef{L}{X83A0356F839C696F}{}
}
\cleardoublepage
\phantomsection
\addcontentsline{toc}{chapter}{Index}
\printindex
\newpage
\immediate\write\pagenrlog{["End"], \arabic{page}];}
\immediate\closeout\pagenrlog
\end{document}
|