concept CSnippet {
  long snippetID;
  S type;
  S title, md5, transpilationMD5;
  bool isPublic;
  
  File file() { ret snippetDB_textFile(snippetID); }
  S text() { ret loadTextFile(file()); }
  bool hasText() { ret fileExists(file()); }
  void setText(S text) {
    S oldText = text();
    if (eq(text, oldText)) ret;
    thread {
      logStructure(javaxBackupDir("snippet-text-changes.log"), ll(now(), snippetID, type, title, md5, "old", oldText, "new", text));
    }
    saveTextFile(file(), text);
  }
  int textLength() { ret hasText() ? (int) fileSize(file()) : -1; }
  S snippetID() { ret fsI(snippetID); }
}