(command.CommandList
  children: [
    (C {<set>} {<-o>} {<nounset>})
    (C {<set>} {<-o>} {<pipefail>})
    (C {<set>} {<-o>} {<errexit>})
    (C {<source>} {<'test/common.sh'>})
    (command.ShFunction
      name: _spec-manifest
      body: 
        (BraceGroup
          children: [
            (command.Pipeline
              children: [
                (command.ForEach
                  iter_name: t
                  iter_words: [{<'spec/'> <Id.Lit_Star '*'> <.test.sh>}]
                  do_arg_iter: F
                  body: (command.DoGroup children:[(C {<echo>} {($ Id.VSub_DollarName '$t')})])
                )
                (C {<gawk>} 
                  {
                    (SQ <'\n'> <'  match($0, "spec/(.*)[.]test.sh", array) {\n'> 
                      <'    name = array[1]\n'> <'    # Nothing passing here\n'> <'    if (name == "extended-glob") next;\n'> <'\n'> 
                      <'    # This was meant for ANTLR.\n'> <'    if (name == "shell-grammar") next;\n'> <'\n'> <'    # Just a demo\n'> 
                      <'    if (name == "blog-other1") next;\n'> <'\n'> <'    print name\n'> <'  }\n'> <'  '>
                    )
                  }
                )
              ]
              negated: F
            )
          ]
        )
    )
    (command.ShFunction
      name: manifest
      body: 
        (BraceGroup
          children: [
            (command.Simple
              words: [{<_spec-manifest>}]
              redirects: [
                (redir
                  op: <Id.Redir_Great '>'>
                  loc: (redir_loc.Fd fd:1)
                  arg: {<'_tmp/spec/MANIFEST.txt'>}
                )
              ]
              do_fork: T
            )
          ]
        )
    )
    (command.ShFunction
      name: run-cases
      body: 
        (BraceGroup
          children: [
            (C {<local>} {<Id.Lit_VarLike 'spec_name='> ($ Id.VSub_Number '$1')})
            (command.Simple
              words: [
                {<run-task-with-status>}
                {<'_tmp/spec/'> (${ Id.VSub_Name spec_name) <.task.txt>}
                {<'test/spec.sh'>}
                {($ Id.VSub_DollarName '$spec_name')}
                {<--format>}
                {<html>}
                {<--stats-file>}
                {<'_tmp/spec/'> (${ Id.VSub_Name spec_name) <.stats.txt>}
                {<--stats-template>}
                {
                  (SQ 
                    <
'%(num_cases)d %(osh_num_passed)d %(osh_num_failed)d %(osh_failures_allowed)d %(osh_ALT_delta)d'
                    >
                  )
                }
              ]
              redirects: [
                (redir
                  op: <Id.Redir_Great '>'>
                  loc: (redir_loc.Fd fd:1)
                  arg: {<'_tmp/spec/'> (${ Id.VSub_Name spec_name) <.html>}
                )
              ]
              do_fork: T
            )
          ]
        )
    )
    (C {<readonly>} {<Id.Lit_VarLike 'NUM_TASKS='> <400>})
    (command.ShFunction
      name: _html-summary
      body: 
        (BraceGroup
          children: [
            (command.Simple
              words: [{<cat>}]
              redirects: [
                (redir
                  op: <Id.Redir_DLess '<<'>
                  loc: (redir_loc.Fd fd:0)
                  arg: 
                    (redir_param.HereDoc
                      here_begin: {<EOF>}
                      here_end_span_id: 273
                      stdin_parts: [
                        <'<!DOCTYPE html>\n'>
                        <'<html>\n'>
                        <'  <head>\n'>
                        <'    <link href='>
                        <Id.Right_DoubleQuote '"'>
                        <'../../web/spec-tests.css'>
                        <Id.Right_DoubleQuote '"'>
                        <' rel='>
                        <Id.Right_DoubleQuote '"'>
                        <stylesheet>
                        <Id.Right_DoubleQuote '"'>
                        <'>\n'>
                        <'  </head>\n'>
                        <'  <body>\n'>
                        <'\n'>
                        <'<p id='>
                        <Id.Right_DoubleQuote '"'>
                        <home-link>
                        <Id.Right_DoubleQuote '"'>
                        <'>\n'>
                        <'  <a href='>
                        <Id.Right_DoubleQuote '"'>
                        <'/'>
                        <Id.Right_DoubleQuote '"'>
                        <'>oilshell.org</a>\n'>
                        <'</p>\n'>
                        <'\n'>
                        <'<h1>Spec Test Results Summary</h1>\n'>
                        <'\n'>
                        <'<table>\n'>
                        <'  <thead>\n'>
                        <'    <tr>\n'>
                        <'      <td>name</td> <td>Exit Code</td> <td>Elapsed Seconds</td>\n'>
                        <'      <td># cases</td> <td>osh # passed</td> <td>osh # failed</td>\n'>
                        <'      <td>osh failures allowed</td>\n'>
                        <'      <td>osh ALT delta</td>\n'>
                        <'    </tr>\n'>
                        <'  </thead>\n'>
                      ]
                    )
                )
              ]
              do_fork: T
            )
            (command.Pipeline
              children: [
                (C {<head>} {<-n>} {($ Id.VSub_DollarName '$NUM_TASKS')} {<'_tmp/spec/MANIFEST.txt'>})
                (C {<awk>} 
                  {
                    (SQ <'\n'> <'  # Awk problem: getline errors are ignored by default!\n'> 
                      <'  function error(path) {\n'> <'    print "Error reading line from file: " path > "/dev/stderr"\n'> <'    exit(1)\n'> <'  }\n'> <'\n'> 
                      <'  {\n'> <'    spec_name = $0\n'> <'\n'> <'    # Read from the task files\n'> 
                      <'    path = ( "_tmp/spec/" spec_name ".task.txt" )\n'> <'    n = getline < path\n'> <'    if (n != 1) {\n'> <'      error(path)\n'> <'    }\n'> 
                      <'    status = $1\n'> <'    wall_secs = $2\n'> <'\n'> <'    path = ( "_tmp/spec/" spec_name ".stats.txt" )\n'> 
                      <'    n = getline < path\n'> <'    if (n != 1) {\n'> <'      error(path)\n'> <'    }\n'> <'    num_cases = $1\n'> 
                      <'    osh_num_passed = $2\n'> <'    osh_num_failed = $3\n'> <'    osh_failures_allowed = $4\n'> <'    osh_ALT_delta = $5\n'> <'\n'> 
                      <'    sum_status += status\n'> <'    sum_wall_secs += wall_secs\n'> <'    sum_num_cases += num_cases\n'> 
                      <'    sum_osh_num_passed += osh_num_passed\n'> <'    sum_osh_num_failed += osh_num_failed\n'> 
                      <'    sum_osh_failures_allowed += osh_failures_allowed\n'> <'    sum_osh_ALT_delta += osh_ALT_delta\n'> <'    num_rows += 1\n'> <'\n'> <'    # For the console\n'> 
                      <'    if (status == 0) {\n'> <'      num_passed += 1\n'> <'    } else {\n'> <'      num_failed += 1\n'> 
                      <'      print spec_name " failed with status " status > "/dev/stderr"\n'> <'    }\n'> <'\n'> <'    if (status != 0) {\n'> <'      css_class = "failed"\n'> 
                      <'    } else if (osh_num_failed != 0) {\n'> <'      css_class = "osh-allow-fail"\n'> <'    } else if (osh_num_passed != 0) {\n'> 
                      <'      css_class = "osh-pass"\n'> <'    } else {\n'> <'      css_class = ""\n'> <'    }\n'> <'    print "<tr class=" css_class ">"\n'> 
                      <'    print "<td><a href=" spec_name ".html>" spec_name "</a></td>"\n'> <'    print "<td>" status "</td>"\n'> <'    print "<td>" wall_secs "</td>"\n'> 
                      <'    print "<td>" num_cases "</td>"\n'> <'    print "<td>" osh_num_passed "</td>"\n'> <'    print "<td>" osh_num_failed "</td>"\n'> 
                      <'    print "<td>" osh_failures_allowed "</td>"\n'> <'    print "<td>" osh_ALT_delta "</td>"\n'> <'    print "</tr>"\n'> <'  }\n'> <'\n'> <'  END {\n'> 
                      <'    print "<tfoot>"\n'> <'    print "<tr>"\n'> <'    print "<td>TOTAL (" num_rows " rows) </td>"\n'> 
                      <'    print "<td>" sum_status "</td>"\n'> <'    print "<td>" sum_wall_secs "</td>"\n'> <'    print "<td>" sum_num_cases "</td>"\n'> 
                      <'    print "<td>" sum_osh_num_passed "</td>"\n'> <'    print "<td>" sum_osh_num_failed "</td>"\n'> 
                      <'    print "<td>" sum_osh_failures_allowed "</td>"\n'> <'    print "<td>" sum_osh_ALT_delta "</td>"\n'> <'    print "</tr>"\n'> <'    print "</tfoot>"\n'> 
                      <'\n'> <'    # For the console\n'> <'    print "" > "/dev/stderr"\n'> <'    if (num_failed == 0) {\n'> 
                      <'      print "*** All " num_passed " tests PASSED" > "/dev/stderr"\n'> <'    } else {\n'> <'      print "*** " num_failed " tests FAILED" > "/dev/stderr"\n'> <'  }\n'> 
                      <'  }\n'> <'  '>
                    )
                  }
                )
              ]
              negated: F
            )
            (command.Simple
              words: [{<cat>}]
              redirects: [
                (redir
                  op: <Id.Redir_DLess '<<'>
                  loc: (redir_loc.Fd fd:0)
                  arg: 
                    (redir_param.HereDoc
                      here_begin: {<EOF>}
                      here_end_span_id: 411
                      stdin_parts: [
                        <'    </table>\n'>
                        <'\n'>
                        <'    <h3>Version Information</h3>\n'>
                        <'    <pre>\n'>
                      ]
                    )
                )
              ]
              do_fork: T
            )
            (C {<'test/spec.sh'>} {<version-text>})
            (command.Simple
              words: [{<cat>}]
              redirects: [
                (redir
                  op: <Id.Redir_DLess '<<'>
                  loc: (redir_loc.Fd fd:0)
                  arg: 
                    (redir_param.HereDoc
                      here_begin: {<EOF>}
                      here_end_span_id: 429
                      stdin_parts: [<'    </pre>\n'> <'  </body>\n'> <'</html>\n'>]
                    )
                )
              ]
              do_fork: T
            )
          ]
        )
    )
    (command.ShFunction
      name: html-summary
      body: 
        (BraceGroup
          children: [
            (command.Simple
              words: [{<_html-summary>}]
              redirects: [
                (redir
                  op: <Id.Redir_Great '>'>
                  loc: (redir_loc.Fd fd:1)
                  arg: {<'_tmp/spec/index.html'>}
                )
              ]
              do_fork: T
            )
            (C {<echo>})
            (C {<echo>} 
              {(DQ <'Results: file://'> ($ Id.VSub_DollarName '$PWD') <'/_tmp/spec/index.html'>)}
            )
          ]
        )
    )
    (command.ShFunction
      name: link-web
      body: 
        (BraceGroup
          children: [
            (C {<ln>} {<-s>} {<-f>} {<--verbose>} {($ Id.VSub_DollarName '$PWD') <'/web'>} {<_tmp>})
          ]
        )
    )
    (command.ShFunction
      name: _all-parallel
      body: 
        (BraceGroup
          children: [
            (C {<mkdir>} {<-p>} {<'_tmp/spec'>})
            (C {<manifest>})
            (command.AndOr
              ops: [Id.Op_DPipe]
              children: [
                (command.Pipeline
                  children: [
                    (C {<head>} {<-n>} {($ Id.VSub_DollarName '$NUM_TASKS')} {<'_tmp/spec/MANIFEST.txt'>})
                    (C {<xargs>} {<-n>} {<1>} {<-P>} {($ Id.VSub_DollarName '$JOBS')} {<--verbose>} {<-->} 
                      {($ Id.VSub_Number '$0')} {<run-cases>}
                    )
                  ]
                  negated: F
                )
                (C {<true>})
              ]
            )
            (C {<all-tests-to-html>})
            (C {<link-web>})
            (C {<html-summary>})
          ]
        )
    )
    (command.ShFunction
      name: all-parallel
      body: 
        (BraceGroup
          children: [(command.TimeBlock pipeline:(C {($ Id.VSub_Number '$0')} {<_all-parallel>}))]
        )
    )
    (command.ShFunction
      name: all-serial
      body: 
        (BraceGroup
          children: [
            (C {<mkdir>} {<-p>} {<'_tmp/spec'>})
            (command.Pipeline
              children: [
                (C {<cat>} {<'_tmp/spec/MANIFEST.txt'>})
                (command.WhileUntil
                  keyword: <Id.KW_While while>
                  cond: 
                    (condition.Shell
                      commands: [(command.Sentence child:(C {<read>} {<t>}) terminator:<Id.Op_Semi _>)]
                    )
                  body: 
                    (command.DoGroup
                      children: [
                        (C {<echo>} {($ Id.VSub_DollarName '$t')})
                        (command.AndOr
                          ops: [Id.Op_DPipe]
                          children: [
                            (command.Simple
                              words: [
                                {<'test/spec.sh'>}
                                {($ Id.VSub_DollarName '$t')}
                                {<--format>}
                                {<html>}
                              ]
                              redirects: [
                                (redir
                                  op: <Id.Redir_Great '>'>
                                  loc: (redir_loc.Fd fd:1)
                                  arg: {<'_tmp/spec/'> (${ Id.VSub_Name t) <.html>}
                                )
                              ]
                              do_fork: T
                            )
                            (BraceGroup
                              children: [
                                (C {<echo>} {(DQ <FAILED>)})
                                (command.ControlFlow
                                  token: <Id.ControlFlow_Exit exit>
                                  arg_word: {<1>}
                                )
                              ]
                            )
                          ]
                        )
                      ]
                    )
                )
              ]
              negated: F
            )
          ]
        )
    )
    (command.ShFunction
      name: _test-to-html
      body: 
        (BraceGroup
          children: [
            (C {<local>} {<Id.Lit_VarLike 'spec_name='> ($ Id.VSub_Number '$1')})
            (command.Simple
              words: [{<cat>}]
              redirects: [
                (redir
                  op: <Id.Redir_DLess '<<'>
                  loc: (redir_loc.Fd fd:0)
                  arg: 
                    (redir_param.HereDoc
                      here_begin: {<EOF>}
                      here_end_span_id: 731
                      stdin_parts: [
                        <'<!DOCTYPE html>\n'>
                        <'<html>\n'>
                        <'  <head>\n'>
                        <'    <link href='>
                        <Id.Right_DoubleQuote '"'>
                        <'../../web/spec-code.css'>
                        <Id.Right_DoubleQuote '"'>
                        <' rel='>
                        <Id.Right_DoubleQuote '"'>
                        <stylesheet>
                        <Id.Right_DoubleQuote '"'>
                        <'>\n'>
                        <'  </head>\n'>
                        <'  <body>\n'>
                        <'    <table>\n'>
                      ]
                    )
                )
              ]
              do_fork: T
            )
            (command.Simple
              words: [
                {<awk>}
                {
                  (SQ <'\n'> <'  { \n'> 
                    <
'    # & is the substitution character.  Why is \\\\& a literal backslash instead\n'
                    > <'    # of \\&?  This changed on the gawk between Ubuntu 14.04 and 16.04.\n'> <'\n'> 
                    <'    gsub("&", "\\\\&amp;");\n'> <'    gsub("<", "\\\\&lt;");\n'> <'    gsub(">", "\\\\&gt;");\n'> <'    line_num = NR\n'> <'\n'> 
                    <'    print "<tr>"\n'> <'    print "<td class=num>" line_num "</td>"\n'> <'    if ($0 ~ /^###/) {\n'> 
                    <'      line = "<span class=comm3>" $0 "</span>"\n'> <'    } else if ($0 ~ /^#/) {\n'> <'      line = "<span class=comm1>" $0 "</span>"\n'> 
                    <'    } else {\n'> <'      line = $0\n'> <'    }\n'> <'    print "<td class=line id=L" line_num ">" line "</td>"\n'> 
                    <'    print "</tr>"\n'> <'  }\n'> <'  '>
                  )
                }
              ]
              redirects: [
                (redir
                  op: <Id.Redir_Less '<'>
                  loc: (redir_loc.Fd fd:0)
                  arg: {<'spec/'> (${ Id.VSub_Name spec_name) <.test.sh>}
                )
              ]
              do_fork: T
            )
            (command.Simple
              words: [{<cat>}]
              redirects: [
                (redir
                  op: <Id.Redir_DLess '<<'>
                  loc: (redir_loc.Fd fd:0)
                  arg: 
                    (redir_param.HereDoc
                      here_begin: {<EOF>}
                      here_end_span_id: 779
                      stdin_parts: [<'    </table>\n'> <'  </body>\n'> <'</html>\n'>]
                    )
                )
              ]
              do_fork: T
            )
          ]
        )
    )
    (command.ShFunction
      name: test-to-html
      body: 
        (BraceGroup
          children: [
            (C {<local>} {<Id.Lit_VarLike 'spec_name='> ($ Id.VSub_Number '$1')})
            (command.Simple
              words: [{<_test-to-html>} {($ Id.VSub_DollarName '$spec_name')}]
              redirects: [
                (redir
                  op: <Id.Redir_Great '>'>
                  loc: (redir_loc.Fd fd:1)
                  arg: {<'_tmp/spec/'> (${ Id.VSub_Name spec_name) <.test.html>}
                )
              ]
              do_fork: T
            )
          ]
        )
    )
    (command.ShFunction
      name: all-tests-to-html
      body: 
        (BraceGroup
          children: [
            (command.AndOr
              ops: [Id.Op_DPipe]
              children: [
                (command.Pipeline
                  children: [
                    (C {<head>} {<-n>} {($ Id.VSub_DollarName '$NUM_TASKS')} {<'_tmp/spec/MANIFEST.txt'>})
                    (C {<xargs>} {<-n>} {<1>} {<-P>} {<8>} {<--verbose>} {<-->} {($ Id.VSub_Number '$0')} 
                      {<test-to-html>}
                    )
                  ]
                  negated: F
                )
                (C {<true>})
              ]
            )
          ]
        )
    )
    (command.If
      arms: [
        (if_arm
          cond: 
            (condition.Shell
              commands: [
                (command.Sentence
                  child: 
                    (C {<test>} 
                      {
                        (DQ 
                          (command_sub
                            left_token: <Id.Left_DollarParen '$('>
                            child: (C {<basename>} {($ Id.VSub_Number '$0')})
                          )
                        )
                      } {<Id.Lit_Equals '='>} {(SQ <spec-runner.sh>)}
                    )
                  terminator: <Id.Op_Semi _>
                )
              ]
            )
          action: [(C {(DQ ($ Id.VSub_At '$@'))})]
          spids: [855 874]
        )
      ]
    )
  ]
)