# This file was created automatically, do not edit!
#############################################################################
##
#W  test.tst                GAP 4 package Browse                Thomas Breuer
#W                                                              Frank Lübeck
##
##  This file contains the GAP code of the examples in the package
##  documentation files.
##  
##  In order to run the tests, one starts GAP from the `tst' subdirectory
##  of the `pkg/Browse' directory, and calls `Test( "test.tst" );'.
##  
gap> LoadPackage( "Browse", false );
true
gap> save:= SizeScreen();;
gap> SizeScreen( [ 72 ] );;
gap> START_TEST( "Input file: test.tst" );

##
gap> oldinterval:= BrowseData.defaults.dynamic.replayDefaults.replayInterval;;
gap> BrowseData.defaults.dynamic.replayDefaults.replayInterval:= 1;;

##  doc/../lib/ncurses.gi (854-867)
gap> win := NCurses.newwin(0,0,0,0);; pan := NCurses.new_panel(win);;
gap> defc := NCurses.defaultColors;;
gap> NCurses.wmove(win, 0, 0);;
gap> for a in defc do for b in defc do
>      NCurses.wattrset(win, NCurses.ColorAttr(a, b));
>      NCurses.waddstr(win, Concatenation(a,"/",b,"\t"));
>    od; od;
gap> if NCurses.IsStdoutATty() then
>      NCurses.update_panels();; NCurses.doupdate();;
>      NCurses.napms(5000);;     # show for 5 seconds
>      NCurses.endwin();; NCurses.del_panel(pan);; NCurses.delwin(win);;
>    fi;

##  doc/../lib/ncurses.gi (118-128)
gap> NCurses.IsAttributeLine( "abc" );
true
gap> NCurses.IsAttributeLine( [ "abc", "def" ] );
false
gap> NCurses.IsAttributeLine( [ NCurses.attrs.UNDERLINE, true, "abc" ] );
true
gap> NCurses.IsAttributeLine( "" );  NCurses.IsAttributeLine( [] );
true
false

##  doc/../lib/ncurses.gi (191-204)
gap> plain_str:= "hello";;
gap> with_attr:= [ NCurses.attrs.BOLD, "bold" ];;
gap> NCurses.ConcatenationAttributeLines( [ plain_str, plain_str ] );
"hellohello"
gap> NCurses.ConcatenationAttributeLines( [ plain_str, with_attr ] );
[ "hello", 2097152, "bold" ]
gap> NCurses.ConcatenationAttributeLines( [ with_attr, plain_str ] );
[ 2097152, "bold", 0, "hello" ]
gap> NCurses.ConcatenationAttributeLines( [ with_attr, with_attr ] );
[ 2097152, "bold", 0, 2097152, "bold" ]
gap> NCurses.ConcatenationAttributeLines( [ with_attr, with_attr ], true );
[ 2097152, "bold", 2097152, "bold" ]

##  doc/../lib/ncurses.gi (316-321)
gap> NCurses.RepeatedAttributeLine( "12345", 23 );
"12345123451234512345123"
gap> NCurses.RepeatedAttributeLine( [ NCurses.attrs.BOLD, "12345" ], 13 );
[ 2097152, "12345", 0, 2097152, "12345", 0, 2097152, "123" ]

##  doc/../lib/ncurses.gi (1087-1093)
gap> NCurses.WidthAttributeLine( "abcde" );
5
gap> NCurses.WidthAttributeLine( [ NCurses.attrs.BOLD, "abc",
>        NCurses.attrs.NORMAL, "de" ] );
5

##  doc/../lib/ncurses.gi (3202-3209)
gap> NCurses.Alert( "Hello world!", 1000 );
fail
gap> NCurses.Alert( [ "Hello world!",
>      [ "Hello ", NCurses.attrs.BOLD, "bold!" ] ], 1500,
>      NCurses.ColorAttr( "red", -1 ) + NCurses.attrs.BOLD );
fail

##  doc/../lib/browse.gi (244-256)
gap> BrowseData.IsBrowseTableCellData( "abc" );
true
gap> BrowseData.IsBrowseTableCellData( [ "abc", "def" ] );
true
gap> BrowseData.IsBrowseTableCellData( rec( rows:= [ "ab", "cd" ],
>                                           align:= "tl" ) );
true
gap> BrowseData.IsBrowseTableCellData( "" );
true
gap> BrowseData.IsBrowseTableCellData( [] );
true

##  doc/../lib/browse.gi (1994-2000)
gap> BrowseData.BlockEntry( "abc", 3, 5 );
[ "     ", "  abc", "     " ]
gap> BrowseData.BlockEntry( rec( rows:= [ "ab", "cd" ],
>                                align:= "tl" ), 3, 5 );
[ "ab   ", "cd   ", "     " ]

##  doc/../lib/browse.gi (438-445)
gap> m:= 10;;  n:= 5;;
gap> xpl1:= rec( work:= rec(
>      main:= List( [ 1 .. m ], i -> List( [ 1 .. n ],
>        j -> String( [ i, j ] ) ) ) ) );;
gap> BrowseData.IsBrowseTable( xpl1 );
true

##  doc/../lib/browse.gi (452-465)
gap> m:= 6;;  n:= 5;;
gap> xpl2:= rec( work:= rec(
>      main:= List( [ 1 .. m ], i -> List( [ 1 .. n ],
>        j -> rec( rows:= List( [ -i*j, i*j*1000+j, i-j ], String ),
>                  align:= "c" ) ) ),
>      labelsRow:= List( [ 1 .. m ], i -> [ String( i ) ] ),
>      labelsCol:= [ List( [ 1 .. n ], String ) ],
>      sepRow:= "-",
>      sepCol:= "|",
>  ) );;
gap> BrowseData.IsBrowseTable( xpl2 );
true

##  doc/../lib/browse.gi (474-514)
gap> m:= 30;;  n:= 25;;
gap> xpl3:= rec( work:= rec(
>      header:= [ "                    Example 3" ],
>      labelsRow:= List( [ 1 .. 30 ], i -> [ String( i ) ] ),
>      sepLabelsRow:= " % ",
>      sepLabelsCol:= "=",
>      sepRow:= "*",
>      sepCol:= " |",
>      footer:= t -> [ Concatenation( "top-left entry is: ",
>                          String( t.dynamic.topleft{ [ 1, 2] } ) ) ],
>  ) );;
gap> if NCurses.attrs.has_colors then
>   xpl3.work.main:= List( [ 1 .. m ], i -> List( [ 1 .. n ],
>     j -> rec( rows:= [ String( -i*j ),
>                        [ NCurses.attrs.BOLD, true,
>                          NCurses.attrs.ColorPairs[56+1], true,
>                          String( i*j*1000+j ),
>                          NCurses.attrs.NORMAL, true ],
>                          String( i-j ) ],
>               align:= "c" ) ) );
>   xpl3.work.labelsCol:= [ List( [ 1 .. 30 ], i -> [
>     NCurses.attrs.ColorPairs[ 56+4 ], true,
>     String( i ),
>     NCurses.attrs.NORMAL, true ] ) ];
> else
>   xpl3.work.main:= List( [ 1 .. m ], i -> List( [ 1 .. n ],
>     j -> rec( rows:= [ String( -i*j ),
>                        [ NCurses.attrs.BOLD, true,
>                          String( i*j*1000+j ),
>                          NCurses.attrs.NORMAL, true ],
>                          String( i-j ) ],
>               align:= "c" ) ) );
>   xpl3.work.labelsCol:= [ List( [ 1 .. 30 ], i -> [
>     NCurses.attrs.BOLD, true,
>     String( i ),
>     NCurses.attrs.NORMAL, true ] ) ];
> fi;
gap> BrowseData.IsBrowseTable( xpl3 );
true

##  doc/../lib/browse.gi (525-543)
gap> xpl4:= rec(
>     defc:= NCurses.defaultColors,
>     wd:= Maximum( List( ~.defc, Length ) ),
>     ca:= NCurses.ColorAttr,
>     work:= rec(
>       header:= [ "Examples of NCurses.ColorAttr" ],
>       main:= List( ~.defc, i -> List( ~.defc,
>         j -> [ [ ~.ca( i, j ), String( i, ~.wd ) ],        # no true!
>                [ ~.ca( i, j ), true, String( "on", ~.wd ) ],
>                [ ~.ca( i, j ), String( j, ~.wd ) ] ] ) ),  # no true!
>       labelsRow:= List( ~.defc, i -> [ String( i ) ] ),
>       labelsCol:= [ List( ~.defc, String ) ],
>       sepRow:= "-",
>       sepCol:= [ " |", "|" ],
>  ) );;
gap> BrowseData.IsBrowseTable( xpl4 );
true

##  doc/../lib/browse.gi (5429-5440)
gap> xpl1.work.ShowHelp:= BrowseData.ShowHelpPager;;
gap> BrowseData.SetReplay( "?Q" );
gap> Unbind( xpl1.dynamic );
gap> NCurses.BrowseGeneric( xpl1 );
gap> xpl1.work.ShowHelp:= BrowseData.ShowHelpTable;;
gap> BrowseData.SetReplay( "?dQQ" );
gap> Unbind( xpl1.dynamic );
gap> NCurses.BrowseGeneric( xpl1 );
gap> BrowseData.SetReplay( false );
gap> Unbind( xpl1.dynamic );

##  doc/../app/matdisp.g (114-130)
gap> n:= [ 14, 14, 14, 14 ];;
gap> input:= Concatenation( n, n, n, "Q" );;  # ``do nothing and quit''
gap> BrowseData.SetReplay( input );
gap> Browse( RandomMat( 10, 10, Integers ) );
gap> BrowseData.SetReplay( input );
gap> Browse( RandomMat( 10, 10, GF(3) ) );
gap> BrowseData.SetReplay( input );
gap> Browse( RandomMat( 10, 10, GF(4) ) );
gap> BrowseData.SetReplay( input );
gap> Browse( RandomMat( 10, 10, Integers mod 6 ) );
gap> BrowseData.SetReplay( input );
gap> Browse( RandomMat( 10, 10, GF( NextPrimeInt( 2^16 ) ) ) );
gap> BrowseData.SetReplay( input );
gap> Browse( RandomMat( 10, 10, GF( 2^20 ) ) );
gap> BrowseData.SetReplay( false );

##  doc/../app/ctbldisp.g (58-80)
gap> if TestPackageAvailability( "CTblLib" ) = true then
>      BrowseData.SetReplay( Concatenation(
>         # scroll in the table
>         "DRULdddddrrrrrlluu",
>         # select an entry and move it around
>         "seddrruuuddlll",
>         # search for the pattern 135 (six times)
>         "/135", [ NCurses.keys.ENTER ], "nnnnn",
>         # deselect the entry, select the first column
>         "qLsc",
>         # sort and categorize by this column
>         "sc",
>         # select the first row, move down the selection
>         "srdddd",
>         # expand the selected category, scroll the selection down
>         "xd",
>         # and quit the application
>         "Q" ) );
>      Browse( CharacterTable( "HN" ) );
>      BrowseData.SetReplay( false );
> fi;

##  doc/../app/ctbldisp.g (770-782)
gap> BrowseData.SetReplay( Concatenation(
>         # select the first entry
>         "se",
>         # scroll in the table
>         "drrrr",
>         # keep the table open for a while
>         [ 14, 14, 14, 14, 14 ],
>         # and quit the application
>         "Q" ) );
gap> BrowseDecompositionMatrix( CharacterTable( "J1" ) mod 2 );
gap> BrowseData.SetReplay( false );

##  doc/../app/tomdisp.g (39-56)
gap> if TestPackageAvailability( "TomLib" ) = true then
>      BrowseData.SetReplay( Concatenation(
>         # scroll in the table
>         "DDRRR",
>         # search for the (exact) value 100 (three times)
>         "/100",
>         [ NCurses.keys.DOWN, NCurses.keys.DOWN, NCurses.keys.RIGHT ],
>         [ NCurses.keys.DOWN, NCurses.keys.DOWN, NCurses.keys.DOWN ],
>         [ NCurses.keys.RIGHT, NCurses.keys.ENTER ], "nn",
>         # no more occurrences of 100, confirm
>         [ NCurses.keys.ENTER ],
>         # and quit the application
>         "Q" ) );
>      Browse( TableOfMarks( "A10" ) );
>      BrowseData.SetReplay( false );
>    fi;

##  doc/../app/atlasbrowse.g (533-563)
gap> d:= [ NCurses.keys.DOWN ];;  r:= [ NCurses.keys.RIGHT ];;
gap> c:= [ NCurses.keys.ENTER ];;
gap> BrowseData.SetReplay( Concatenation(
>        "/A5",         # Find the string A5 ...
>        d, d, r,       # ... such that just the word matches,
>        c,             # start the search,
>        c,             # click the table entry A5,
>        d, d,          # move down two rows,
>        c,             # click the row for this representation,
>        "Q",           # quit the second level table,
>        d, d,          # move down two rows,
>        c,             # click the table entry A6,
>        d,             # move down one row,
>        c,             # click the first row,
>        "Q",           # quit the second level table,
>        "Q" ) );       # and quit the application.
gap> if IsBound( BrowseAtlasInfo ) and IsBound( AtlasProgramInfo ) then
>      SetUserPreference( "AtlasRep", "AtlasRepMarkNonCoreData", "" );
>      tworeps:= BrowseAtlasInfo();
>    else
>      tworeps:= [ fail ];
>    fi;
gap> BrowseData.SetReplay( false );
gap> if fail in tworeps then
>      Print( "no access to the Web ATLAS\n" );
>    else
>      Print( List( tworeps, x -> x.identifier[1] ), "\n" );
>    fi;
[ "A5", "A6" ]

##  doc/../app/manual.g (67-79)
gap> n:= [ 14, 14, 14 ];;  # ``do nothing''
gap> BrowseData.SetReplay( Concatenation(
>        "xdxd",                             # expand a Tutorial section
>        n, "Q" ) );                         # and quit
gap> BrowseGapManuals( "inline/collapsed" );
gap> BrowseData.SetReplay( Concatenation(
>        "/Browse", [ NCurses.keys.ENTER ],  # search for "Browse"
>        "xdxddxd",                          # expand a section
>        n, "Q" ) );                         # and quit
gap> BrowseGapManuals( "inline/collapsed" );
gap> BrowseData.SetReplay( false );

##  doc/../app/gapbibl.g (361-363)
gap> file:= Filename( DirectoriesLibrary( "doc" ), "manualbib.xml" );;

##  doc/../app/gapbibl.g (401-413)
gap> # sort and categorize by year, scroll down, expand a category row
gap> BrowseData.SetReplay( "scrrscsedddddxdddddQ" );
gap> BrowseBibliography();;
gap> # sort & categorize by authors, expand all category rows, scroll down
gap> BrowseData.SetReplay( "scscXseddddddQ" );
gap> BrowseBibliography();;
gap> # sort and categorize by journal, search for a journal name, expand
gap> BrowseData.SetReplay( Concatenation( "scrrrsc/J. Algebra",
>        [ NCurses.keys.ENTER ], "nxdddQ" ) );
gap> BrowseBibliography();;
gap> BrowseData.SetReplay( false );

##  doc/../app/profile.g (54-75)
gap> n:= [ 14, 14, 14, 14, 14 ];;  # ``do nothing''
gap> ProfileOperationsAndMethods( true );    # collect some data
gap> ConjugacyClasses( PrimitiveGroup( 24, 1 ) );;
gap> ProfileOperationsAndMethods( false );
gap> BrowseData.SetReplay( Concatenation(
>        "e",                                    # edit threshold paras
>        [ NCurses.keys.DC ], "2", "\t",         # replace 10000 by 20000
>        [ NCurses.keys.DC ], "2",               # replace 30 by 20
>        [ NCurses.keys.ENTER ],                 # commit the changes
>        "scso",                                 # sort by column 1,
>        n,
>        "rso",                                  # sort by column 2,
>        n,
>        "rso",                                  # sort by column 3,
>        n,
>        "q",                                    # deselect the column,
>        "/Normalizer", [ NCurses.keys.ENTER ],  # search for a function,
>        n, n, n, "Q" ) );                       # and quit
gap> BrowseProfile();
gap> BrowseData.SetReplay( false );

##  doc/../app/userpref.g (258-274)
gap> d:= [ NCurses.keys.DOWN ];;  
gap> c:= [ NCurses.keys.ENTER ];; 
gap> BrowseData.SetReplay( Concatenation(
>        "/PackagesToLoad",  # enter a search string,
>        c,                  # start the search,
>        c,                  # edit the entry (a list of choices),
>        " ", d,             # toggle the first four values,
>        " ", d,             #
>        " ", d,             #
>        " ", d,             #
>        c,                  # submit the values,
>        "Q",                # quit the table,
>        c ) );              # choose "cancel": do not apply the changes.
gap> BrowseUserPreferences();
gap> BrowseData.SetReplay( false );

##  doc/../app/gapdata.g (133-145)
gap> n:= [ 14, 14, 14 ];;  # ``do nothing''
gap> # open the overview of Conway polynomials
gap> BrowseData.SetReplay( Concatenation( "/Conway Polynomials",
>      [ NCurses.keys.ENTER, NCurses.keys.ENTER ], "srdddd", n, "Q" ) );
gap> BrowseGapData();;
gap> # open the overview of GAP packages
gap> BrowseData.SetReplay( Concatenation( "/GAP Packages",
>      [ NCurses.keys.ENTER, NCurses.keys.ENTER ], "/Browse",
>      [ NCurses.keys.ENTER ], "n", n, "Q" ) );
gap> BrowseGapData();;
gap> BrowseData.SetReplay( false );

##  doc/../app/filetree.g (107-119)
gap> n:= [ 14, 14, 14 ];;  # ``do nothing''
gap> BrowseData.SetReplay( Concatenation(
>        "q",                                  # leave the selection
>        "X",                                  # expand all categories
>        "/filetree", [ NCurses.keys.ENTER ],  # search for "filetree"
>        n, "Q" ) );                           # and quit
gap> dir:= DirectoriesPackageLibrary( "Browse", "" )[1];;
gap> if IsBound( BrowseDirectory ) then
>      BrowseDirectory( dir );
>    fi;
gap> BrowseData.SetReplay( false );

##  doc/../app/puzzle.g (87-92)
gap> BrowseData.SetReplay( Concatenation(
>        BrowsePuzzleSolution.steps, "Q" ) );
gap> BrowsePuzzle( 4, 4, BrowsePuzzleSolution.init );;
gap> BrowseData.SetReplay( false );

##  doc/../app/solitair.g (121-131)
gap> for n in [ 33, 37, 45 ] do
>      BrowseData.SetReplay( Concatenation(
>          PegSolitaireSolutions.( String( n ) ), "Q" ) );
>      PegSolitaire( n );
>      PegSolitaire( "large", n );
>      PegSolitaire( n, true );
>      PegSolitaire( "large", n, true );
> od;
gap> BrowseData.SetReplay( false );

##  doc/../app/rubik.g (92-101)
gap> cubegens := [
>   ( 1, 3, 8, 6)( 2, 5, 7, 4)( 9,33,25,17)(10,34,26,18)(11,35,27,19),
>   ( 9,11,16,14)(10,13,15,12)( 1,17,41,40)( 4,20,44,37)( 6,22,46,35),
>   (17,19,24,22)(18,21,23,20)( 6,25,43,16)( 7,28,42,13)( 8,30,41,11),
>   (25,27,32,30)(26,29,31,28)( 3,38,43,19)( 5,36,45,21)( 8,33,48,24),
>   (33,35,40,38)(34,37,39,36)( 3, 9,46,32)( 2,12,47,29)( 1,14,48,27),
>   (41,43,48,46)(42,45,47,44)(14,22,30,38)(15,23,31,39)(16,24,32,40)
> ];;

##  doc/../app/rubik.g (143-156)
gap> choice:= List( [ 1 .. 30 ], i -> Random( [ 1 .. 6 ] ) );;
gap> input:= List( "tlfrbd", IntChar ){ choice };;
gap> BrowseData.SetReplay( Concatenation(
>        input{ [ 1 .. 20 ] },
>        "s",                    # switch to number display
>        input{ [ 21 .. 25 ] },
>        "s",                    # switch to color display
>        input{ [ 26 .. 30 ] },
>        "Q" ) );;               # quit the browse table
gap> BrowseRubiksCube( Product( cubegens{ choice } ) );;
gap> BrowseRubiksCube( "large", Product( cubegens{ choice } ) );;
gap> BrowseData.SetReplay( false );

##  doc/../app/knight.g (77-83)
gap> for entry in BrowseChangeSidesSolutions do
>      BrowseData.SetReplay( Concatenation( entry, "Q" ) );
>      BrowseChangeSides();
> od;
gap> BrowseData.SetReplay( false );

##  doc/../app/sudoku.g (236-239)
gap> game := Sudoku.Init(" 3   68  | 85  1 69|  97   53|      79 |\
>  6  47   |45  2    |89   2 1 | 4   8 7 | ");;

##  doc/../app/sudoku.g (267-276)
gap> game := Sudoku.Init(" 3   68  | 85  1 69|  97   53|      79 |\
>  6  47   |45  2    |89   2 1 | 4   8 7 | ");;
gap> Sudoku.Place(game, 1, 3);; # 3 is already in first row
gap> IsBound(game.impossible);
true
gap> Sudoku.Place(game, 1, 2);; # 2 is not in row, col or subsquare
gap> IsBound(game.impossible);
false

##  doc/../app/sudoku.g (295-301)
gap> Sudoku.RandomGame(5833750);
[ " 1         2     43  2   68   72    8     6 2   1 9 8  8 3   9     \
47 3   7  18  ", 5833750 ]
gap> last = Sudoku.RandomGame(last[2]);
true

##  doc/../app/sudoku.g (311-326)
gap> game := Sudoku.Init(" 3   68  | 85  1 69|  97   53|      79 |\
>  6  47   |45  2    |89   2 1 | 4   8 7 | ");;
gap> Sudoku.SimpleDisplay(game);
 3 |  6|8  
 85|  1| 69
  9|7  | 53
-----------
   |   |79 
 6 | 47|   
45 | 2 |   
-----------
89 |  2| 1 
 4 |  8| 7 
   |   |   

##  doc/../app/sudoku.g (407-423)
gap> s := "      5  | 154 6 2 |9   5 3  |6 4      |   8     |8  9   53\
> |     5   | 4   7  2|  91  8  ";;
gap> sol := Sudoku.UniqueSolution(Sudoku.Init(s));;
gap> Sudoku.SimpleDisplay(sol);
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

##  doc/../app/wizard.g (567-591)
gap> d:= [ NCurses.keys.DOWN ];;  r:= [ NCurses.keys.RIGHT ];;
gap> c:= [ NCurses.keys.ENTER ];;
gap> BrowseData.SetReplay( Concatenation(
>        c,             # confirm the initial message
>        d,             # enter the first step
>        d, d,          # go to the choice of classical groups
>        c,             # confirm this choice
>        c,             # enter the next step
>        d, d,          # go to the choice of unitary groups
>        c,             # confirm this choice
>        c,             # enter the next step
>        "5", c,        # enter the dimension and confirm
>        c,             # enter the next step
>        "3", c,        # enter the field size and confirm
>        c ) );         # confirm all choices (closes the table)
gap> res:= BrowseWizard( rec(
>      steps:= BrowseData.ChooseSimpleGroupQuestions,
>      defaults:= rec(),
>      header:= "Choose a finite simple group" ) );;
gap> BrowseData.SetReplay( false );
gap> BrowseData.InterpretSimpleGroupDescription( res );
rec( parameter := [ 4, 3 ], requestedname := "U5(3)", series := "2A", 
  shortname := "U5(3)" )

##  doc/../app/rldemo.g (55-62)
gap> dirs := DirectoriesPackageLibrary("Browse");;
gap> demofile := Filename(dirs, "../app/demo.demo");;
gap> if IsBound(GAPInfo.UseReadline) and GAPInfo.UseReadline = true then
>   LoadDemoFile("My first demo", demofile);
>   LoadDemoFile("My first demo (single lines)", demofile, true);
> fi;

##  doc/brdbattr.xml (93-99)
gap> n:= 100;;
gap> smallintenum1:= DatabaseIdEnumerator( rec(
>      identifiers:= [ 1 .. n ],
>      entry:= function( dbidenum, id ) return id; end,
>    ) );;

##  doc/brdbattr.xml (111-122)
gap> DatabaseAttributeAdd( smallintenum1, rec(
>      identifier:= "primes",
>      type:= "values",
>      name:= "IsPrimeInt",
>    ) );
gap> DatabaseAttributeAdd( smallintenum1, rec(
>      identifier:= "prime powers",
>      type:= "values",
>      name:= "IsPrimePowerInt",
>    ) );

##  doc/brdbattr.xml (126-132)
gap> DatabaseAttributeAdd( smallintenum1, rec(
>      identifier:= "factors",
>      type:= "values",
>      name:= "Factors",
>    ) );

##  doc/brdbattr.xml (140-146)
gap> DatabaseAttributeAdd( smallintenum1, rec(
>      identifier:= "residue mod 11",
>      type:= "values",
>      create:= function( attr, id ) return id mod 11; end,
>    ) );

##  doc/brdbattr.xml (156-171)
gap> factorialdata:= function( n )
>      local result, i, f;
>      result:= [];  i:= 1;  f:= 1;;
>      while f <= n do
>        Add( result, [ f, i ] );  i:= i + 1;  f:= f * i;
>      od;
>      return result;
>    end;;
gap> DatabaseAttributeAdd( smallintenum1, rec(
>      identifier:= "inverse factorial",
>      type:= "pairs",
>      data:= rec( automatic:= factorialdata( n ), nonautomatic:= [] ),
>      isSorted:= true,
>    ) );

##  doc/brdbattr.xml (183-188)
gap> t1:= BrowseTableFromDatabaseIdEnumerator( smallintenum1,
>           [ "self" ],
>           [ "primes", "prime powers", "factors", "residue mod 11",
>             "inverse factorial" ] );;

##  doc/brdbattr.xml (192-207)
gap> nop:= [ 14, 14, 14, 14, 14, 14 ];;  # ``do nothing''
gap> sample_session:= Concatenation(
>         # categorize by the first column, expand categories, wait, reset
>         nop, "scsc", nop, "X", nop, "!",
>         # sort the residue column, wait, reset
>         "scrrrso", nop, "!",
>         # categorize by the inverse factorial column
>         "rscsrdx", nop, "!",
>         # and quit the application
>         "qQ" );;
gap> BrowseData.SetReplay( sample_session );
gap> NCurses.BrowseGeneric( t1 );
gap> BrowseData.SetReplay( false );
gap> Unbind( t1.dynamic.replay );

##  doc/brdbattr.xml (256-320)
gap> smallintenum2:= DatabaseIdEnumerator( rec(
>      identifiers:= [ 1 .. n ],
>      entry:= function( dbidenum, id ) return id; end,
>      viewLabel:= "",
>    ) );;
gap> DatabaseAttributeAdd( smallintenum2, rec(
>      identifier:= "primes",
>      type:= "values",
>      name:= "IsPrimeInt",
>      viewLabel:= "prime?",
>      viewValue:= value -> BrowseData.ReplacedEntry( value,
>          [ true, false ], [ "+", "-" ] ),
>      sortParameters:= [ "add counter on categorizing", "yes" ],
>      align:= "c",
>      categoryValue:= value -> BrowseData.ReplacedEntry( value,
>          [ true, false ], [ "prime", "nonprime" ] ),
>    ) );
gap> DatabaseAttributeAdd( smallintenum2, rec(
>      identifier:= "prime powers",
>      type:= "values",
>      name:= "IsPrimePowerInt",
>      viewLabel:= "prime power?",
>      viewValue:= value -> BrowseData.ReplacedEntry( value,
>          [ true, false ], [ "+", "-" ] ),
>      sortParameters:= [ "add counter on categorizing", "yes" ],
>      align:= "c",
>      categoryValue:= value -> BrowseData.ReplacedEntry( value,
>          [ true, false ], [ "prime power", "not prime power" ] ),
>    ) );
gap> DatabaseAttributeAdd( smallintenum2, rec(
>      identifier:= "factors",
>      type:= "values",
>      name:= "Factors",
>      viewLabel:= "factors",
>      viewValue:= value -> JoinStringsWithSeparator( List( value, String ),
>                                                     " * "),
>      widthCol:= 10,
>    ) );
gap> DatabaseAttributeAdd( smallintenum2, rec(
>      identifier:= "residue mod 11",
>      type:= "values",
>      create:= function( attr, id ) return id mod 11; end,
>      viewSort:= BrowseData.SortAsIntegers,
>      categoryValue:= res -> Concatenation( String( res ), " mod 11" ),
>    ) );
gap> DatabaseAttributeAdd( smallintenum2, rec(
>      identifier:= "inverse factorial",
>      type:= "pairs",
>      data:= rec( automatic:= factorialdata( n ), nonautomatic:= [] ),
>      isSorted:= true,
>      categoryValue:= function( k )
>        if k = "" then
>          return "(no factorial)";
>        else
>          return Concatenation( String( k ), "!" );
>        fi;
>      end,
>    ) );
gap> t2:= BrowseTableFromDatabaseIdEnumerator( smallintenum2,
>           [ "self" ],
>           [ "primes", "prime powers", "factors", "residue mod 11",
>             "inverse factorial" ],
>           t -> BrowseData.HeaderWithRowCounter( t, "Small integers", n ) );;

##  doc/brdbattr.xml (324-329)
gap> BrowseData.SetReplay( sample_session );
gap> NCurses.BrowseGeneric( t2 );
gap> BrowseData.SetReplay( false );
gap> Unbind( t2.dynamic.replay );

##  doc/brdbattr.xml (352-390)
gap> DatabaseAttributeAdd( smallintenum2, rec(
>      identifier:= "primes & prime powers",
>      type:= "values",
>      create:= function( attr, id )
>        if   IsPrimeInt( id ) then
>          return 2;
>        elif IsPrimePowerInt( id ) then
>          return 1;
>        else
>          return 0;
>        fi;
>      end,
>      viewLabel:= [ NCurses.attrs.BOLD + NCurses.ColorAttr( "red", -1 ),
>                    "prime", NCurses.attrs.NORMAL, " power?" ],
>      viewValue:= value -> BrowseData.ReplacedEntry( value,
>          [ 0, 1, 2 ], [ "-", "+",
>                         [ NCurses.attrs.BOLD + NCurses.ColorAttr( "red", -1 ),
>                           true, "+",
>                           NCurses.ColorAttr( "red", -1 ), false ] ] ),
>      sortParameters:= [ "add counter on categorizing", "yes" ],
>      align:= "c",
>      categoryValue:= value -> BrowseData.ReplacedEntry( value,
>          [ 0, 1, 2 ],
>          [ "not prime power", "prime power, not prime", "prime" ] ),
>    ) );
gap> t3:= BrowseTableFromDatabaseIdEnumerator( smallintenum2,
>           [ "self" ],
>           [ "primes & prime powers", "residue mod 11",
>             "inverse factorial" ],
>           t -> BrowseData.HeaderWithRowCounter( t, "Small integers", n ) );;
gap> sample_session2:= Concatenation(
>         # categorize by the first column, expand categories, wait, reset
>         nop, "scsc", nop, "X", nop, "!", "Q" );;
gap> BrowseData.SetReplay( sample_session2 );
gap> NCurses.BrowseGeneric( t3 );
gap> BrowseData.SetReplay( false );
gap> Unbind( t3.dynamic.replay );

##  doc/brdbattr.xml (404-486)
gap> smallintenum3:= DatabaseIdEnumerator( rec(
>     identifiers:= [ 1 .. n ],
>     entry:= function( dbidenum, id ) return id; end,
>     viewLabel:= "",
>     version:= n,
>     update:= function( dbidenum )
>         dbidenum.identifiers:= [ 1 .. n ];
>         dbidenum.version:= n;
>         return true;
>       end,
>     ) );;
gap> updateByUnbindData:= function( attr )
>      Unbind( attr.data );
>      return true;
>    end;;
gap> DatabaseAttributeAdd( smallintenum3, rec(
>     identifier:= "primes",
>     type:= "values",
>     name:= "IsPrimeInt",
>     viewLabel:= "prime?",
>     viewValue:= value -> BrowseData.ReplacedEntry( value,
>         [ true, false ], [ "+", "-" ] ),
>     sortParameters:= [ "add counter on categorizing", "yes" ],
>     align:= "c",
>     categoryValue:= value -> BrowseData.ReplacedEntry( value,
>         [ true, false ], [ "prime", "nonprime" ] ),
>     version:= n,
>     update:= updateByUnbindData,
>     ) );
gap> DatabaseAttributeAdd( smallintenum3, rec(
>     identifier:= "prime powers",
>     type:= "values",
>     name:= "IsPrimePowerInt",
>     viewLabel:= "prime power?",
>     viewValue:= value -> BrowseData.ReplacedEntry( value,
>         [ true, false ], [ "+", "-" ] ),
>     sortParameters:= [ "add counter on categorizing", "yes" ],
>     align:= "c",
>     categoryValue:= value -> BrowseData.ReplacedEntry( value,
>         [ true, false ], [ "prime power", "not prime power" ] ),
>     version:= n,
>     update:= updateByUnbindData,
>     ) );
gap> DatabaseAttributeAdd( smallintenum3, rec(
>     identifier:= "factors",
>     type:= "values",
>     name:= "Factors",
>     viewLabel:= "factors",
>     viewValue:= value -> JoinStringsWithSeparator( List( value, String ),
>                                                    " * "),
>     widthCol:= 10,
>     version:= n,
>     update:= updateByUnbindData,
>     ) );
gap> DatabaseAttributeAdd( smallintenum3, rec(
>     identifier:= "residue mod 11",
>     type:= "values",
>     create:= function( attr, id ) return id mod 11; end,
>     viewSort:= BrowseData.SortAsIntegers,
>     categoryValue:= res -> Concatenation( String( res ), " mod 11" ),
>     version:= n,
>     update:= updateByUnbindData,
>     ) );
gap> DatabaseAttributeAdd( smallintenum3, rec(
>     identifier:= "inverse factorial",
>     type:= "pairs",
>     data:= rec( automatic:= factorialdata( n ), nonautomatic:= [] ),
>     isSorted:= true,
>     categoryValue:= function( k )
>       if k = "" then
>         return "(no factorial)";
>       else
>         return Concatenation( String( k ), "!" );
>       fi;
>     end,
>     version:= n,
>     update:= function( attr )
>         attr.data.automatic:= factorialdata( n );
>         return true;
>       end,
>     ) );

##  doc/brdbattr.xml (492-504)
gap> n:= 200;;
gap> DatabaseIdEnumeratorUpdate( smallintenum3 );
true
gap> t4:= BrowseTableFromDatabaseIdEnumerator( smallintenum3,
>   [ "self" ], [ "primes", "prime powers", "factors", "residue mod 11",
>     "inverse factorial" ],
>   t -> BrowseData.HeaderWithRowCounter( t, "Small integers", n ) );;
gap> BrowseData.SetReplay( sample_session );
gap> NCurses.BrowseGeneric( t4 );
gap> BrowseData.SetReplay( false );
gap> Unbind( t4.dynamic.replay );

##  doc/../app/tmdbattr.g (49-74)
gap> c:= [ NCurses.keys.ENTER ];;
gap> n:= [ 14, 14, 14 ];;  # ``do nothing''
gap> BrowseData.SetReplay( Concatenation(
>        "scrrsc",   # categorize the list by source tables of fusions,
>        "srdd",     # choose a source table,
>        "x",        # expand the list of targets of fusions
>        n,
>        "!",        # revert the categorization
>        "q",        # leave the mode in which a row is selected
>        "scrrrrsc", # categorize the list by filenames
>        "X",        # expand all categories
>        n,
>        "!",        # revert the categorization
>        "scso",     # sort the list by group order
>        n,
>        "!q",       # revert the sorting and selection
>        "?",        # open the help window
>        n,
>        "Q",        # close the help window
>        "/A5", c,   # search for the first occurrence of "A5"
>        n,
>        "Q" ) );;   # and quit the browse table
gap> BrowseTomLibInfo();
gap> BrowseData.SetReplay( false );

##
gap> BrowseData.defaults.dynamic.replayDefaults.replayInterval:= oldinterval;;

##
gap> STOP_TEST( "test.tst" );
gap> SizeScreen( save );;

#############################################################################
##
#E
