docs: def add(self, func, **kwargs):
          """
          Parse func's function source code as Python and Markdown cells.
          :param func: Python function to parse
          :param kwargs: variables to inject as first Python cell
          :return:
          """
  
          params = set(kwargs.keys())
          func_params = set(inspect.getargspec(func).args)
  
          # ignore self, which is present when extending Notebook.
          if 'self' in func_params:
              func_params.remove('self')
  
          if params != func_params:
              fatal('Params {} not matching cells function params {}'.format(list(params), list(func_params)))
  
          lines = inspect.getsourcelines(func)[0][1:]
  
          buffer = ""
          indent_count = None
          inside_markdown = False
          return_found = False
  
          for line in lines:
  
              # remove base indentation of function 'func'
              if len(line.strip()) > 0:
                  if not indent_count:
                      indent_count = 0
                      for c in line:
                          if c not in [' ', '\t']:
                              break
                          else:
                              indent_count += 1
                  line = line[indent_count:]
  
              if not inside_markdown and line.strip() == "return":
                  logging.info('Encountered "return" statement, ignoring the rest of the notebook.')
                  break
  
              if line.strip() == "'''":  # if md block begin/end, or new cell...
                  if len(buffer.strip()) > 0:
                      if not inside_markdown:  # if md block begin: new markdown block! flush buffer
                          self.add_cell_code(buffer)
                      else:  # if md block end: markdown block completed! flush buffer
                          self.add_cell_markdown(buffer)
                  buffer = ""
                  inside_markdown = not inside_markdown
              else:
                  buffer += line
  
          if len(buffer.strip()) > 0:
              if not inside_markdown:
                  self.add_cell_code(buffer)
              else:
                  self.add_cell_markdown(buffer)
  
          if len(kwargs) > 0:
              # We have parameters to inject into the notebook.
              # If the first cell is Markdown, assume that is the title and
              # insert parameters as 2nd cell. Otherwise, as 1st cell.
              if len(self.nb['cells']) > 0 and self.nb['cells'][0].cell_type == 'markdown':
                  self.add_cell_params(kwargs, 1)
              else:
                  self.add_cell_params(kwargs, 0)