public void preloadArticle(ArticleRef articleRef, OperationObserver observer)
     throws ParseException {
   Article article = loadArticle(articleRef, observer);
   for (SubArticleRef subArticle : article.getSubArticles()) {
     if (subArticle.isLocked()) continue;
     if (subArticle.isPdf()) {
       loadPdf(subArticle, articleRef, observer);
     } else {
       loadSubArticleHtml(subArticle, observer);
     }
   }
 }
 public File loadPdf(
     SubArticleRef subArticleRef, ArticleRef articleRef, OperationObserver observer)
     throws ParseException {
   if (!subArticleRef.isPdf())
     throw new IllegalArgumentException("Sub article is not PDF: " + subArticleRef);
   File pdfFile = getPdfFile(subArticleRef);
   if (pdfFile.exists()) return pdfFile;
   loginIfAvailable(observer);
   TestDe.downloadPdf(subArticleRef, articleRef, pdfFile, observer);
   return pdfFile;
 }
 public String loadSubArticleHtml(SubArticleRef ref, OperationObserver observer) {
   loginIfAvailable(observer);
   return loadSubArticleHtml(ref.getPageRef(), observer);
 }
 public void clearSubArticle(SubArticleRef subArticleRef) {
   articlePagesCache.delete(subArticleRef.getPageRef());
 }
 private File getPdfFile(SubArticleRef ref) {
   String filename = Str.toFileCompatibleString(ref.getPageRef());
   return storage.getFile(filename);
 }