docs: def add(self, title="", keywords="", content="", attachments="", due="", book=1, privacy=0, date="", modified=""):
          ''' Add a note to the database.  The title should be short (perhaps 3
          to 7 words).  The keywords are comma-separated, and should be similar
          in style to others in the database.  The content may be of any length. The
          attachments are comma-separated, and must be full pathnames to files 
          that exist.'''
          #self.debug = 1
          try:
              known_books = []
              for b in self.cur.execute("SELECT number FROM book;").fetchall():
                  known_books.extend(b)
          except:
              self.error("cannot look up list of known books")
          #print("known_books %s" % known_books)
          #print("book %s initially" % book)
          if not book in known_books:
              if book != -1:
                  self.warning("the book is not known, so switching to \"Default\"")
              book = 1
          #print("book %s later" % book)
          self.fyi("add with title='%s'" % title)
          self.fyi("add with keywords='%s'" % keywords)
          self.fyi("add with attachments='%s' (comma-separated string)" % attachments)
          self.fyi("add with due='%s'" % due)
          self.fyi("add with book='%s'" % book)
          if not isinstance(due, str):
              due = ""
          due = self.interpret_time(due)[0]
          self.fyi("due: %s" % due)
          now = datetime.datetime.now()
          if date == "":
              date = now.strftime("%Y-%m-%d %H:%M:%S")
          try:
              self.cur.execute("INSERT INTO note(authorId, date, modified, title, content, privacy, due, book) VALUES(?, ?, ?, ?, ?, ?, ?, ?);",
                  (self.authorId, date, modified, title, content, 0, due, book))
          except:
              self.error("error adding note to the database")
          noteId = self.cur.lastrowid
          self.fyi("noteId: %s" % noteId)
          hash = self.compute_hash(noteId=noteId, date=date, title=title)
          self.fyi("hash: %s" % hash)
          try:
              self.cur.execute("UPDATE note SET hash=? WHERE noteId=?;", (hash, noteId))
          except:
              self.error("error adding note hash to the database")
          for keyword in keywords:
              self.fyi("  inserting keyword:", keyword)
              keywordId = self.con.execute("SELECT keywordId FROM keyword WHERE keyword = ?;", [keyword]).fetchone()
              if keywordId:
                  self.fyi("  (existing keyword with id %s)" % keywordId)
                  keywordId = keywordId[0]
              else:
                  self.fyi("  (new keyword)")
                  self.cur.execute("INSERT INTO keyword(keyword) VALUES (?);", [keyword])
                  keywordId = self.cur.lastrowid
              self.con.execute("INSERT INTO notekeyword(noteId, keywordID) VALUES(?, ?)", [noteId, keywordId])
          # Handle attachments, which must be existing files.
          attachments = [key.lstrip().rstrip() for key in attachments.split(',')]
          attachments = filter(None, attachments) # remove blanks
          for attachment in attachments:
              self.fyi("processing attachment '%s'" % attachment)
              if not os.path.isfile(attachment):
                  self.warning(" cannot attach file '%s' because it does not exist" % attachment)
              else:
                  self.fyi("    '%s' exists" % attachment)
                  attachment = os.path.expanduser(attachment)
                  afile = open(attachment, "rb")
                  try:
                      blob = afile.read()
                      self.fyi("    read file '%s'" % attachment)
                      self.cur.execute('INSERT INTO attachment(filename,contents) VALUES(?,?)', [attachment,buffer(blob)])
                      attachmentId = self.cur.lastrowid
                      self.fyi("    inserted OK; attachmentID=%d" % attachmentId)
                      self.con.commit()
                      self.fyi("    added to attachment table")
                      self.fyi('    try "INSERT INTO note_attachment(noteId, attachmentId) VALUES(%d,%d)"' % (noteId,attachmentId))
                      self.cur.execute('INSERT INTO note_attachment(noteId, attachmentId) VALUES(?,?)', [noteId,attachmentId])
                      self.con.commit()
                      self.fyi("    ... OK")
                  except:
                      self.error("Problem storing attachment named '%s'" % attachment)
                  finally:
                      afile.close()
                  self.fyi(" ... all done, writing attachment")
          self.con.commit()
          self.fyi("add() returning noteId=%d ... is all ok?" % noteId)
          return noteId