Thread

  1. [PATCH v3 3/3] psql: Fix counting of header and footer lines in pager setup

    Erik Wienhold <ewie@ewie.name> — 2025-09-09T00:36:49Z

    * The table header only produces extra lines when printed in normal
      mode.  So don't count those lines in tuples_only mode or expanded
      mode.
    
    * Count the lines of the table title, if present.
    
    * Count all footer lines instead of treating each footer as a single
      line.
    ---
     src/fe_utils/print.c | 39 +++++++++++++++++++++++++++------------
     1 file changed, 27 insertions(+), 12 deletions(-)
    
    diff --git a/src/fe_utils/print.c b/src/fe_utils/print.c
    index 82f4fc9af20..94043fae663 100644
    --- a/src/fe_utils/print.c
    +++ b/src/fe_utils/print.c
    @@ -3394,15 +3394,8 @@ IsPagerNeeded(const printTableContent *cont, unsigned int *width_wrap,
     				   NULL, &nl_lines, NULL);
     
     		header_height[i] = nl_lines;
    -
    -		if (nl_lines > max_lines)
    -			max_lines = nl_lines;
     	}
     
    -	/* Add height of tallest header column */
    -	lines += max_lines;
    -	max_lines = 0;
    -
     	/* Scan all cells to count their lines */
     	for (i = 0, cell = cont->cells; *cell; cell++)
     	{
    @@ -3449,12 +3442,34 @@ IsPagerNeeded(const printTableContent *cont, unsigned int *width_wrap,
     	{
     		printTableFooter *f;
     
    -		/*
    -		 * FIXME -- this is slightly bogus: it counts the number of
    -		 * footers, not the number of lines in them.
    -		 */
    +		if (cont->title)
    +		{
    +			pg_wcssize((const unsigned char *) cont->title, strlen(cont->title),
    +					   cont->opt->encoding, NULL, &nl_lines, NULL);
    +			lines += nl_lines;
    +		}
    +
    +		if (!expanded)
    +		{
    +			/* Find the tallest header column */
    +			for (i = 0; i < cont->ncolumns; i++)
    +			{
    +				if (header_height[i] > max_lines)
    +					max_lines = header_height[i];
    +			}
    +
    +			/* Add height of tallest header column */
    +			lines += max_lines;
    +			max_lines = 0;
    +		}
    +
    +		/* Count all footer lines */
     		for (f = cont->footers; f; f = f->next)
    -			lines++;
    +		{
    +			pg_wcssize((const unsigned char *) f->data, strlen(f->data),
    +					   cont->opt->encoding, NULL, &nl_lines, NULL);
    +			lines += nl_lines;
    +		}
     	}
     
     	*fout = PageOutput(lines, cont->opt);
    -- 
    2.51.0
    
    
    --h4pjkjw5wkhovhea
    Content-Type: text/plain; charset=us-ascii
    Content-Disposition: attachment; filename="test-psql-pager.py"
    
    # This script runs different test cases through psql to find the maximum number
    # of lines that still trigger psql to use the pager.
    #
    # Termios is used to set the terminal size.
    #
    # Use environment variable PATH to select the psql binary to test.  Use libpq
    # environment variables to select a database for testing in which this script
    # can run the test setup.
    
    import argparse
    import os
    import os.path
    import subprocess
    import sys
    import tempfile
    import time
    import termios
    import typing
    
    
    def run_tests(outfile):
        # Prepare database schema
        proc = subprocess.run(['psql', '-X'], text=True, input=r'''
    \set ON_ERROR_STOP on
    BEGIN;
    
    CREATE OR REPLACE FUNCTION generate_lines(n int)
        RETURNS TABLE (lines text)
        LANGUAGE sql
        AS $$ SELECT string_agg(s::text, e'\n') FROM generate_series(1, n) s $$;
    
    -- This creates a view name and column name with 24 line breaks when truncated
    -- to the default NAMEDATALEN (63 = 9*2 + 15*3)
    SELECT format('CREATE OR REPLACE VIEW %I (c) AS SELECT null;'
                  'CREATE OR REPLACE VIEW nl_column (%1$I) AS SELECT null;',
                  string_agg(s::text, e'\n'))
    FROM generate_series(1, current_setting('max_identifier_length')::int) s
    \gexec
    
    COMMIT;
    ''').check_returncode()
    
        testcases = []
        for cmd in commands:
            # Repeat each command with every combination of flags that affect the
            # number of output lines.
            for flags in range(1 << 3):
                testcases.append(Testcase(
                    cmd=cmd,
                    unaligned=flags & 1,
                    tuples_only=flags & (1 << 1),
                    expanded=flags & (1 << 2),
                ))
    
        # Remember current term size
        save_term_size = termios.tcgetwinsize(sys.stdout.fileno())
    
        max_paged_lines = []
        for tc in testcases:
            max_paged_lines.append(find_max_paged_lines(tc.psql_args()))
    
        # Restore term size
        termios.tcsetwinsize(sys.stdout.fileno(), save_term_size)
    
        # Print the testcase results
        for tc, lines in zip(testcases, max_paged_lines):
            flags = ''
            flags += 'A' if tc.unaligned else '-'
            flags += 't' if tc.tuples_only else '-'
            flags += 'x' if tc.expanded else '-'
            # Make sure we get one output line per testcase
            cmd = tc.cmd.replace('\n', r'\n')
            print(f"{lines:2}  {flags}  {cmd}", file=outfile)
    
    
    def run_psql_with_pager(args):
        with tempfile.NamedTemporaryFile() as tmp:
            mtime_before = os.stat(tmp.name).st_mtime_ns
            env = {
                # Inherit environment variables (especially PATH and libpq-specific
                # ones).
                **os.environ,
                # Set PAGER so that we can tell from the temp file's mtime that the
                # pager was triggered.
                'PAGER': f'touch {tmp.name}',
            }
            proc = subprocess.run(['psql', '-X', *args], env=env)
            if proc.returncode:
                return None
            mtime_after = os.stat(tmp.name).st_mtime_ns
        pager_used = mtime_after > mtime_before
        return pager_used
    
    
    def find_max_paged_lines(psql_args):
        # Binary search the maximum number of lines at which psql still triggers
        # the pager.
        min_lines = 1
        max_lines = 100
        cols = 100  # sufficient for our test cases
        while min_lines <= max_lines:
            lines = min_lines + (max_lines - min_lines) // 2
            termios.tcsetwinsize(sys.stdout.fileno(), (lines, cols))
            pager_used = run_psql_with_pager(psql_args)
            if pager_used is None:
                return -1
            if pager_used:
                min_lines = lines + 1
            else:
                max_lines = lines - 1
        return max_lines
    
    
    class Testcase(typing.NamedTuple):
        cmd: str
        unaligned: bool
        tuples_only: bool
        expanded: bool
    
        def psql_args(self):
            args = ['-c', self.cmd]
            if self.unaligned:
                args.append('-A')
            if self.tuples_only:
                args.append('-t')
            if self.expanded:
                args.append('-x')
            return args
    
    
    # The SQL and meta commands we will be testing
    commands = [
        'SELECT * FROM generate_lines(25)',
        'SELECT * FROM nl_column',
        '\\d nl_column',
        '\\d+ nl_column',
        '\\d "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n"',
        '\\d+ "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n"',
    ]
    
    parser = argparse.ArgumentParser()
    parser.add_argument('expectfile', metavar='FILE', help="file with expected test results")
    args = parser.parse_args()
    
    basename, _ = os.path.splitext(args.expectfile)
    outfile = basename + '.tmp'
    difffile = basename + '.diff'
    
    with open(outfile, 'w') as fp:
        run_tests(fp)
    
    with open(difffile, 'w') as fp:
        if os.path.isfile(args.expectfile):
            srcfile = args.expectfile
        else:
            srcfile = os.devnull
        proc = subprocess.run(['diff', '-u', srcfile, outfile], stdout=fp)
    
    if proc.returncode:
        print()
        print("Test output does not match the expected output.")
        print(f'The differences can be viewed in file "{difffile}".')
        exit(1)
    
    --h4pjkjw5wkhovhea
    Content-Type: text/plain; charset=us-ascii
    Content-Disposition: attachment; filename="0-master.out"
    
    27  ---  SELECT * FROM generate_lines(25)
     2  A--  SELECT * FROM generate_lines(25)
    27  -t-  SELECT * FROM generate_lines(25)
     2  At-  SELECT * FROM generate_lines(25)
     2  --x  SELECT * FROM generate_lines(25)
     2  A-x  SELECT * FROM generate_lines(25)
     2  -tx  SELECT * FROM generate_lines(25)
     2  Atx  SELECT * FROM generate_lines(25)
    27  ---  SELECT * FROM nl_column
     2  A--  SELECT * FROM nl_column
    27  -t-  SELECT * FROM nl_column
     2  At-  SELECT * FROM nl_column
     2  --x  SELECT * FROM nl_column
     2  A-x  SELECT * FROM nl_column
     2  -tx  SELECT * FROM nl_column
     2  Atx  SELECT * FROM nl_column
    27  ---  \d nl_column
     2  A--  \d nl_column
    27  -t-  \d nl_column
     2  At-  \d nl_column
    27  --x  \d nl_column
     2  A-x  \d nl_column
    27  -tx  \d nl_column
     2  Atx  \d nl_column
    29  ---  \d+ nl_column
     4  A--  \d+ nl_column
    27  -t-  \d+ nl_column
     2  At-  \d+ nl_column
    29  --x  \d+ nl_column
     4  A-x  \d+ nl_column
    27  -tx  \d+ nl_column
     2  Atx  \d+ nl_column
     3  ---  \d "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n"
     2  A--  \d "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n"
     3  -t-  \d "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n"
     2  At-  \d "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n"
     3  --x  \d "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n"
     2  A-x  \d "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n"
     3  -tx  \d "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n"
     2  Atx  \d "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n"
     5  ---  \d+ "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n"
     4  A--  \d+ "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n"
     3  -t-  \d+ "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n"
     2  At-  \d+ "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n"
     5  --x  \d+ "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n"
     4  A-x  \d+ "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n"
     3  -tx  \d+ "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n"
     2  Atx  \d+ "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n"
    
    --h4pjkjw5wkhovhea
    Content-Type: text/plain; charset=us-ascii
    Content-Disposition: attachment; filename="1-refactor.out"
    
    27  ---  SELECT * FROM generate_lines(25)
    27  A--  SELECT * FROM generate_lines(25)
    27  -t-  SELECT * FROM generate_lines(25)
    27  At-  SELECT * FROM generate_lines(25)
    27  --x  SELECT * FROM generate_lines(25)
    27  A-x  SELECT * FROM generate_lines(25)
    27  -tx  SELECT * FROM generate_lines(25)
    27  Atx  SELECT * FROM generate_lines(25)
    27  ---  SELECT * FROM nl_column
    27  A--  SELECT * FROM nl_column
    27  -t-  SELECT * FROM nl_column
    27  At-  SELECT * FROM nl_column
    27  --x  SELECT * FROM nl_column
    27  A-x  SELECT * FROM nl_column
    27  -tx  SELECT * FROM nl_column
    27  Atx  SELECT * FROM nl_column
    27  ---  \d nl_column
    27  A--  \d nl_column
    27  -t-  \d nl_column
    27  At-  \d nl_column
    27  --x  \d nl_column
    27  A-x  \d nl_column
    27  -tx  \d nl_column
    27  Atx  \d nl_column
    29  ---  \d+ nl_column
    29  A--  \d+ nl_column
    27  -t-  \d+ nl_column
    27  At-  \d+ nl_column
    29  --x  \d+ nl_column
    29  A-x  \d+ nl_column
    27  -tx  \d+ nl_column
    27  Atx  \d+ nl_column
     3  ---  \d "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n"
     3  A--  \d "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n"
     3  -t-  \d "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n"
     3  At-  \d "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n"
     3  --x  \d "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n"
     3  A-x  \d "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n"
     3  -tx  \d "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n"
     3  Atx  \d "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n"
     5  ---  \d+ "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n"
     5  A--  \d+ "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n"
     3  -t-  \d+ "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n"
     3  At-  \d+ "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n"
     5  --x  \d+ "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n"
     5  A-x  \d+ "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n"
     3  -tx  \d+ "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n"
     3  Atx  \d+ "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n"
    
    --h4pjkjw5wkhovhea
    Content-Type: text/plain; charset=us-ascii
    Content-Disposition: attachment; filename="2-expanded.out"
    
    27  ---  SELECT * FROM generate_lines(25)
    27  A--  SELECT * FROM generate_lines(25)
    27  -t-  SELECT * FROM generate_lines(25)
    27  At-  SELECT * FROM generate_lines(25)
    27  --x  SELECT * FROM generate_lines(25)
    27  A-x  SELECT * FROM generate_lines(25)
    27  -tx  SELECT * FROM generate_lines(25)
    27  Atx  SELECT * FROM generate_lines(25)
    27  ---  SELECT * FROM nl_column
    27  A--  SELECT * FROM nl_column
    27  -t-  SELECT * FROM nl_column
    27  At-  SELECT * FROM nl_column
    51  --x  SELECT * FROM nl_column
    51  A-x  SELECT * FROM nl_column
    51  -tx  SELECT * FROM nl_column
    51  Atx  SELECT * FROM nl_column
    27  ---  \d nl_column
    27  A--  \d nl_column
    27  -t-  \d nl_column
    27  At-  \d nl_column
    27  --x  \d nl_column
    27  A-x  \d nl_column
    27  -tx  \d nl_column
    27  Atx  \d nl_column
    29  ---  \d+ nl_column
    29  A--  \d+ nl_column
    27  -t-  \d+ nl_column
    27  At-  \d+ nl_column
    29  --x  \d+ nl_column
    29  A-x  \d+ nl_column
    27  -tx  \d+ nl_column
    27  Atx  \d+ nl_column
     3  ---  \d "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n"
     3  A--  \d "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n"
     3  -t-  \d "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n"
     3  At-  \d "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n"
     3  --x  \d "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n"
     3  A-x  \d "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n"
     3  -tx  \d "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n"
     3  Atx  \d "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n"
     5  ---  \d+ "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n"
     5  A--  \d+ "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n"
     3  -t-  \d+ "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n"
     3  At-  \d+ "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n"
     5  --x  \d+ "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n"
     5  A-x  \d+ "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n"
     3  -tx  \d+ "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n"
     3  Atx  \d+ "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n"
    
    --h4pjkjw5wkhovhea
    Content-Type: text/plain; charset=us-ascii
    Content-Disposition: attachment; filename="3-header-footer.out"
    
    27  ---  SELECT * FROM generate_lines(25)
    27  A--  SELECT * FROM generate_lines(25)
    26  -t-  SELECT * FROM generate_lines(25)
    26  At-  SELECT * FROM generate_lines(25)
    26  --x  SELECT * FROM generate_lines(25)
    26  A-x  SELECT * FROM generate_lines(25)
    26  -tx  SELECT * FROM generate_lines(25)
    26  Atx  SELECT * FROM generate_lines(25)
    27  ---  SELECT * FROM nl_column
    27  A--  SELECT * FROM nl_column
     2  -t-  SELECT * FROM nl_column
     2  At-  SELECT * FROM nl_column
    26  --x  SELECT * FROM nl_column
    26  A-x  SELECT * FROM nl_column
    26  -tx  SELECT * FROM nl_column
    26  Atx  SELECT * FROM nl_column
    28  ---  \d nl_column
    28  A--  \d nl_column
    26  -t-  \d nl_column
    26  At-  \d nl_column
    28  --x  \d nl_column
    28  A-x  \d nl_column
    26  -tx  \d nl_column
    26  Atx  \d nl_column
    54  ---  \d+ nl_column
    54  A--  \d+ nl_column
    26  -t-  \d+ nl_column
    26  At-  \d+ nl_column
    54  --x  \d+ nl_column
    54  A-x  \d+ nl_column
    26  -tx  \d+ nl_column
    26  Atx  \d+ nl_column
    28  ---  \d "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n"
    28  A--  \d "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n"
     2  -t-  \d "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n"
     2  At-  \d "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n"
    28  --x  \d "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n"
    28  A-x  \d "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n"
     2  -tx  \d "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n"
     2  Atx  \d "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n"
    30  ---  \d+ "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n"
    30  A--  \d+ "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n"
     2  -t-  \d+ "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n"
     2  At-  \d+ "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n"
    30  --x  \d+ "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n"
    30  A-x  \d+ "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n"
     2  -tx  \d+ "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n"
     2  Atx  \d+ "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n"
    
    --h4pjkjw5wkhovhea--