docs: def _table_viewer(table, rows_per_page=25, fields=None):
    """  Return a table viewer.
  
      This includes a static rendering of the first page of the table, that gets replaced
      by the charting code in environments where Javascript is executable and BQ is available.
  
    Args:
      table: the table to view.
      rows_per_page: how many rows to display at one time.
      fields: an array of field names to display; default is None which uses the full schema.
    Returns:
      A string containing the HTML for the table viewer.
    """
  
    # TODO(gram): rework this to use google.datalab.utils.commands.chart_html
  
    if not table.exists():
      raise Exception('Table %s does not exist' % table.full_name)
  
    if not table.is_listable():
      return "Done"
  
    _HTML_TEMPLATE = u"""
      <div class="bqtv" id="{div_id}">{static_table}</div>
      <br />{meta_data}<br />
      <script src="/static/components/requirejs/require.js"></script>
      <script>
        require.config({{
          paths: {{
            base: '/static/base',
            d3: '//cdnjs.cloudflare.com/ajax/libs/d3/3.4.13/d3',
            plotly: 'https://cdn.plot.ly/plotly-1.5.1.min.js?noext',
            jquery: '//ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min'
          }},
          map: {{
            '*': {{
              datalab: 'nbextensions/gcpdatalab'
            }}
          }},
          shim: {{
            plotly: {{
              deps: ['d3', 'jquery'],
              exports: 'plotly'
            }}
          }}
        }});
  
        require(['datalab/charting', 'datalab/element!{div_id}', 'base/js/events',
            'datalab/style!/nbextensions/gcpdatalab/charting.css'],
          function(charts, dom, events) {{
            charts.render('gcharts', dom, events, '{chart_style}', [], {data},
              {{
                pageSize: {rows_per_page},
                cssClassNames:  {{
                  tableRow: 'gchart-table-row',
                  headerRow: 'gchart-table-headerrow',
                  oddTableRow: 'gchart-table-oddrow',
                  selectedTableRow: 'gchart-table-selectedrow',
                  hoverTableRow: 'gchart-table-hoverrow',
                  tableCell: 'gchart-table-cell',
                  headerCell: 'gchart-table-headercell',
                  rowNumberCell: 'gchart-table-rownumcell'
                }}
              }},
              {{source_index: {source_index}, fields: '{fields}'}},
              0,
              {total_rows});
          }}
        );
      </script>
    """
  
    if fields is None:
      fields = google.datalab.utils.commands.get_field_list(fields, table.schema)
    div_id = google.datalab.utils.commands.Html.next_id()
    meta_count = ('rows: %d' % table.length) if table.length >= 0 else ''
    meta_name = table.full_name if table.job is None else ('job: %s' % table.job.id)
    if table.job:
      if table.job.cache_hit:
        meta_cost = 'cached'
      else:
        bytes = bigquery._query_stats.QueryStats._size_formatter(table.job.bytes_processed)
        meta_cost = '%s processed' % bytes
      meta_time = 'time: %.1fs' % table.job.total_time
    else:
      meta_cost = ''
      meta_time = ''
  
    data, total_count = google.datalab.utils.commands.get_data(table, fields, first_row=0,
                                                               count=rows_per_page)
  
    if total_count < 0:
      # The table doesn't have a length metadata property but may still be small if we fetched less
      # rows than we asked for.
      fetched_count = len(data['rows'])
      if fetched_count < rows_per_page:
        total_count = fetched_count
  
    chart = 'table' if 0 <= total_count <= rows_per_page else 'paged_table'
    meta_entries = [meta_count, meta_time, meta_cost, meta_name]
    meta_data = '(%s)' % (', '.join([entry for entry in meta_entries if len(entry)]))
  
    return _HTML_TEMPLATE.format(div_id=div_id,
                                 static_table=google.datalab.utils.commands.HtmlBuilder
                                 .render_chart_data(data),
                                 meta_data=meta_data,
                                 chart_style=chart,
                                 source_index=google.datalab.utils.commands
                                 .get_data_source_index(table.full_name),
                                 fields=','.join(fields),
                                 total_rows=total_count,
                                 rows_per_page=rows_per_page,
                                 data=json.dumps(data, cls=google.datalab.utils.JSONEncoder))