docs: def _udf_cell(args, js):
    """Implements the bigquery_udf cell magic for ipython notebooks.
  
    The supported syntax is:
    %%bigquery udf --module <var>
    <js function>
  
    Args:
      args: the optional arguments following '%%bigquery udf'.
      js: the UDF declaration (inputs and outputs) and implementation in javascript.
    Returns:
      The results of executing the UDF converted to a dataframe if no variable
      was specified. None otherwise.
    """
    variable_name = args['module']
    if not variable_name:
      raise Exception('Declaration must be of the form %%bigquery udf --module <variable name>')
  
    # Parse out the input and output specification
    spec_pattern = r'\{\{([^}]+)\}\}'
    spec_part_pattern = r'[a-z_][a-z0-9_]*'
  
    specs = re.findall(spec_pattern, js)
    if len(specs) < 2:
      raise Exception('The JavaScript must declare the input row and output emitter parameters '
                      'using valid jsdoc format comments.\n'
                      'The input row param declaration must be typed as {{field:type, field2:type}} '
                      'and the output emitter param declaration must be typed as '
                      'function({{field:type, field2:type}}.')
  
    inputs = []
    input_spec_parts = re.findall(spec_part_pattern, specs[0], flags=re.IGNORECASE)
    if len(input_spec_parts) % 2 != 0:
      raise Exception('Invalid input row param declaration. The jsdoc type expression must '
                      'define an object with field and type pairs.')
    for n, t in zip(input_spec_parts[0::2], input_spec_parts[1::2]):
      inputs.append((n, t))
  
    outputs = []
    output_spec_parts = re.findall(spec_part_pattern, specs[1], flags=re.IGNORECASE)
    if len(output_spec_parts) % 2 != 0:
      raise Exception('Invalid output emitter param declaration. The jsdoc type expression must '
                      'define a function accepting an an object with field and type pairs.')
    for n, t in zip(output_spec_parts[0::2], output_spec_parts[1::2]):
      outputs.append((n, t))
  
    # Look for imports. We use a non-standard @import keyword; we could alternatively use @requires.
    # Object names can contain any characters except \r and \n.
    import_pattern = r'@import[\s]+(gs://[a-z\d][a-z\d_\.\-]*[a-z\d]/[^\n\r]+)'
    imports = re.findall(import_pattern, js)
  
    # Split the cell if necessary. We look for a 'function(' with no name and a header comment
    # block with @param and assume this is the primary function, up to a closing '}' at the start
    # of the line. The remaining cell content is used as support code.
    split_pattern = r'(.*)(/\*.*?@param.*?@param.*?\*/\w*\n\w*function\w*\(.*?^}\n?)(.*)'
    parts = re.match(split_pattern, js, re.MULTILINE | re.DOTALL)
    support_code = ''
    if parts:
      support_code = (parts.group(1) + parts.group(3)).strip()
      if len(support_code):
        js = parts.group(2)
  
    # Finally build the UDF object
    udf = datalab.bigquery.UDF(inputs, outputs, variable_name, js, support_code, imports)
    datalab.utils.commands.notebook_environment()[variable_name] = udf