Beispiel #1
0
        public void Setup()
        {
            var locations = new List <string>();

            locations.Add(BloomFileLocator.GetFactoryXMatterDirectory());
            _xMatterParentFolder = new TemporaryFolder("UserCollection");
            _xMatterFolder       = new TemporaryFolder(_xMatterParentFolder, "User-XMatter");
            locations.Add(_xMatterParentFolder.Path);
            RobustFile.WriteAllText(Path.Combine(_xMatterFolder.Path, "SomeRandomXYZABCStyles.css"), "Some arbitrary test data");
            RobustFile.WriteAllText(Path.Combine(_xMatterFolder.Path, "Decodable Reader.css"), "Fake DR test data");
            //locations.Add(XMatterAppDataFolder);
            //locations.Add(XMatterCommonDataFolder);
            _xMatterFinder = new XMatterPackFinder(locations);

            _otherFilesForTestingFolder = new TemporaryFolder("BloomFileLocatorTests");
            var userInstalledSearchPaths = new List <string>(ProjectContext.GetFoundFileLocations());

            userInstalledSearchPaths.Add(_otherFilesForTestingFolder.Path);
            _fileLocator = new BloomFileLocator(new CollectionSettings(), _xMatterFinder, ProjectContext.GetFactoryFileLocations(), userInstalledSearchPaths,
                                                ProjectContext.GetAfterXMatterFileLocations());

            //Without this, tests can interact with one another, leaving the language set as something unexpected.
            LocalizationManager.SetUILanguage("en", false);
        }
Beispiel #2
0
        public void Setup()
        {
            Logger.Init();
            _folder = new TemporaryFolder("BloomServerTests");
            LocalizationManager.UseLanguageCodeFolders = true;
            var localizationDirectory = FileLocationUtilities.GetDirectoryDistributedWithApplication("localization");

            _localizationManager = LocalizationManager.Create(TranslationMemory.XLiff, "fr", "Bloom", "Bloom", "1.0.0", localizationDirectory, "SIL/Bloom", null, "", new string[] { });


            ErrorReport.IsOkToInteractWithUser = false;
            _collectionPath = Path.Combine(_folder.Path, "TestCollection");
            var cs = new CollectionSettings(Path.Combine(_folder.Path, "TestCollection.bloomCollection"));

            _fileLocator = new BloomFileLocator(cs, new XMatterPackFinder(new string[] { BloomFileLocator.GetFactoryXMatterDirectory() }), ProjectContext.GetFactoryFileLocations(),
                                                ProjectContext.GetFoundFileLocations(), ProjectContext.GetAfterXMatterFileLocations());
        }
        public static int Handle(HydrateParameters options)
        {
            if (!Directory.Exists(options.Path))
            {
                if (options.Path.Contains(".htm"))
                {
                    Debug.WriteLine("Supply only the directory, not the path to the file.");
                    Console.Error.WriteLine("Supply only the directory, not the path to the file.");
                }
                else
                {
                    Debug.WriteLine("Could not find " + options.Path);
                    Console.Error.WriteLine("Could not find " + options.Path);
                }
                return(1);
            }
            Console.WriteLine("Starting Hydrating.");

            var layout = new Layout
            {
                SizeAndOrientation = SizeAndOrientation.FromString(options.SizeAndOrientation)
            };

            var collectionSettings = new CollectionSettings
            {
                XMatterPackName     = options.XMatter,
                Language1Iso639Code = options.VernacularIsoCode,
                Language2Iso639Code = options.NationalLanguage1IsoCode,
                Language3Iso639Code = options.NationalLanguage2IsoCode
            };

            XMatterPackFinder xmatterFinder = new XMatterPackFinder(new[] { BloomFileLocator.GetInstalledXMatterDirectory() });
            var locator = new BloomFileLocator(collectionSettings, xmatterFinder, ProjectContext.GetFactoryFileLocations(),
                                               ProjectContext.GetFoundFileLocations(), ProjectContext.GetAfterXMatterFileLocations());

            var bookInfo = new BookInfo(options.Path, true);
            var book     = new Book.Book(bookInfo, new BookStorage(options.Path, locator, new BookRenamedEvent(), collectionSettings),
                                         null, collectionSettings, null, null, new BookRefreshEvent());

            if (collectionSettings.XMatterPackName == "Video")
            {
                if (null == book.OurHtmlDom.SelectSingleNodeHonoringDefaultNS("//script[contains(text(),'bloomPlayer.js')]"))
                {
                    var element = book.OurHtmlDom.Head.AppendChild(book.OurHtmlDom.RawDom.CreateElement("script")) as XmlElement;
                    element.IsEmpty = false;
                    element.SetAttribute("type", "text/javascript");
                    element.SetAttribute("src", "bloomPlayer.js");
                }

                AddRequisiteJsFiles(options.Path);
            }

            //we might change this later, or make it optional, but for now, this will prevent surprises to processes
            //running this CLI... the folder name won't change out from under it.
            book.LockDownTheFileAndFolderName = true;

            book.SetLayout(layout);
            book.BringBookUpToDate(new NullProgress());
            Console.WriteLine("Finished Hydrating.");
            Debug.WriteLine("Finished Hydrating.");
            return(0);
        }
Beispiel #4
0
        public static void ChangeLayoutForAllContentPagesInAllBooks(IProgress progress, string collectionPath, string bookPath, string pageGuid)
        {
            if (!File.Exists(bookPath))
            {
                MessageBox.Show("Could not find template book " + bookPath);
                return;
            }
            if (!File.Exists(collectionPath))
            {
                MessageBox.Show("Could not find collection file " + collectionPath);
                return;
            }
            var problems                    = new StringBuilder();
            var collectionFolder            = Path.GetDirectoryName(collectionPath);
            var collection                  = new BookCollection(collectionFolder, BookCollection.CollectionType.TheOneEditableCollection, new BookSelection());
            var collectionSettings          = new CollectionSettings(collectionPath);
            XMatterPackFinder xmatterFinder = new XMatterPackFinder(new[] { BloomFileLocator.GetInstalledXMatterDirectory() });
            var locator = new BloomFileLocator(collectionSettings, xmatterFinder, ProjectContext.GetFactoryFileLocations(),
                                               ProjectContext.GetFoundFileLocations(), ProjectContext.GetAfterXMatterFileLocations());

            var templateBookInfo = new BookInfo(Path.GetDirectoryName(bookPath), true);
            var templateBook     = new Book.Book(templateBookInfo, new BookStorage(templateBookInfo.FolderPath, locator, new BookRenamedEvent(), collectionSettings),
                                                 null, collectionSettings, null, null, new BookRefreshEvent());

            var   pageDictionary = templateBook.GetTemplatePagesIdDictionary();
            IPage page           = null;

            if (!pageDictionary.TryGetValue(pageGuid, out page))
            {
                MessageBox.Show("Could not find template page " + pageGuid);
                return;
            }

            int i = 0;

            foreach (var bookInfo in collection.GetBookInfos())
            {
                i++;
                try
                {
                    var book = new Book.Book(bookInfo,
                                             new BookStorage(bookInfo.FolderPath, locator, new BookRenamedEvent(), collectionSettings),
                                             null, collectionSettings, null, null, new BookRefreshEvent());
                    //progress.WriteMessage("Processing " + book.TitleBestForUserDisplay + " " + i + "/" + collection.GetBookInfos().Count());
                    progress.ProgressIndicator.PercentCompleted = i * 100 / collection.GetBookInfos().Count();

                    book.ChangeLayoutForAllContentPages(page);
                }
                catch (Exception ex)
                {
                    Debug.WriteLine(ex.Message);
                    Console.WriteLine(ex.Message);
                    Console.WriteLine(ex.StackTrace);
                    problems.AppendLine(Path.GetFileName(bookInfo.FolderPath));
                }
            }
            if (problems.Length == 0)
            {
                MessageBox.Show("All books converted successfully");
            }
            else
            {
                MessageBox.Show("Bloom had problems converting the following books; please check them:\n" + problems);
            }
        }
 public void Setup()
 {
     SIL.Reporting.ErrorReport.IsOkToInteractWithUser = false;
     _folder      = new TemporaryFolder("BookCollectionTests");
     _fileLocator = new BloomFileLocator(new CollectionSettings(), new XMatterPackFinder(new string[] {}), ProjectContext.GetFactoryFileLocations(),
                                         ProjectContext.GetFoundFileLocations(), ProjectContext.GetAfterXMatterFileLocations());
     _collection = new BookCollection(_folder.Path, BookCollection.CollectionType.TheOneEditableCollection, new BookSelection());
 }
        public void Setup()
        {
            _librarySettings = new Moq.Mock <CollectionSettings>();
            _librarySettings.SetupGet(x => x.IsSourceCollection).Returns(false);
            _librarySettings.SetupGet(x => x.Language1Iso639Code).Returns("xyz");
            _librarySettings.SetupGet(x => x.Language2Iso639Code).Returns("fr");
            _librarySettings.SetupGet(x => x.Language3Iso639Code).Returns("es");
            _librarySettings.SetupGet(x => x.XMatterPackName).Returns("Factory");
            ErrorReport.IsOkToInteractWithUser = false;
            _projectFolder = new TemporaryFolder("BookStarterTests_ProjectCollection");
            var collectionSettings = new CollectionSettings(Path.Combine(_projectFolder.Path, "test.bloomCollection"));

            var xmatterFinder = new XMatterPackFinder(new [] { BloomFileLocator.GetInstalledXMatterDirectory() });

            _fileLocator = new BloomFileLocator(collectionSettings, xmatterFinder, ProjectContext.GetFactoryFileLocations(), ProjectContext.GetFoundFileLocations(), ProjectContext.GetAfterXMatterFileLocations());


            _starter = new BookStarter(_fileLocator, (dir, forSelectedBook) => new BookStorage(dir, _fileLocator, new BookRenamedEvent(), collectionSettings), _librarySettings.Object);
            _shellCollectionFolder = new TemporaryFolder("BookStarterTests_ShellCollection");
        }
        public BookServer CreateBookServer()
        {
            _collectionSettings = CreateDefaultCollectionsSettings();
            var xmatterFinder = new XMatterPackFinder(new[] { BloomFileLocator.GetInstalledXMatterDirectory() });
            var fileLocator   = new BloomFileLocator(_collectionSettings, xmatterFinder, ProjectContext.GetFactoryFileLocations(), ProjectContext.GetFoundFileLocations(), ProjectContext.GetAfterXMatterFileLocations());
            var starter       = new BookStarter(fileLocator, (dir, forSelectedBook) => new BookStorage(dir, fileLocator, new BookRenamedEvent(), _collectionSettings), _collectionSettings);

            return(new BookServer(
                       //book factory
                       (bookInfo, storage) =>
            {
                return new Bloom.Book.Book(bookInfo, storage, null, _collectionSettings,
                                           new PageSelection(),
                                           new PageListChangedEvent(), new BookRefreshEvent());
            },

                       // storage factory
                       (path, forSelectedBook) =>
            {
                var storage = new BookStorage(path, fileLocator, new BookRenamedEvent(), _collectionSettings);
                storage.BookInfo = new BookInfo(path, true);
                return storage;
            },

                       // book starter factory
                       () => starter,

                       // configurator factory
                       null));
        }
Beispiel #8
0
        public static int Handle(HydrateParameters options)
        {
            if (!Directory.Exists(options.Path))
            {
                if (options.Path.Contains(".htm"))
                {
                    Debug.WriteLine("Supply only the directory, not the path to the file.");
                    Console.Error.WriteLine("Supply only the directory, not the path to the file.");
                }
                else
                {
                    Debug.WriteLine("Could not find " + options.Path);
                    Console.Error.WriteLine("Could not find " + options.Path);
                }
                return(1);
            }
            Console.WriteLine("Starting Hydrating.");

            var layout = new Layout
            {
                SizeAndOrientation = SizeAndOrientation.FromString(options.SizeAndOrientation)
            };

            if (File.Exists(TeamCollectionManager.GetTcLinkPathFromLcPath(Path.GetDirectoryName(options.Path))))
            {
                throw new ApplicationException("Hydrate command cannot currently be used in Team Collections");
                // To make this possible, we'd need to spin up a TeamCollectionManager and TeamCollection and pass the latter
                // to the Book as its SaveContext and still changes would be forbidden unless the book was checked out.
            }

            var collectionSettings = new CollectionSettings
            {
                XMatterPackName     = options.XMatter,
                Language1Iso639Code = options.VernacularIsoCode,
                Language2Iso639Code = string.IsNullOrWhiteSpace(options.NationalLanguage1IsoCode) ? options.VernacularIsoCode : options.NationalLanguage1IsoCode,
                Language3Iso639Code = options.NationalLanguage2IsoCode
            };

            XMatterPackFinder xmatterFinder = new XMatterPackFinder(new[] { BloomFileLocator.GetFactoryXMatterDirectory(), });
            var locator = new BloomFileLocator(collectionSettings, xmatterFinder, ProjectContext.GetFactoryFileLocations(),
                                               ProjectContext.GetFoundFileLocations(), ProjectContext.GetAfterXMatterFileLocations());

            // alwaysSaveable is fine here, as we already checked it's not a TC.
            var bookInfo = new BookInfo(options.Path, true, new AlwaysEditSaveContext());
            var book     = new Book.Book(bookInfo, new BookStorage(options.Path, locator, new BookRenamedEvent(), collectionSettings),
                                         null, collectionSettings, null, null, new BookRefreshEvent(), new BookSavedEvent());
            // This was added as part of the phase 1 changes towards the new language system, where book languages
            // are more clearly distinct from collection languages, and there's no sense (except underlying storage) in which
            // a book has languages that are not selected for display. This made it necessary to decide explicitly
            // whether passing the national language options implies that a book is bi- or tri-lingual. Andrew and I (JohnT)
            // could not think of any reason to pass the arguments at all except to achieve that, so I made it so.
            var langs = new List <string>();

            langs.Add(options.VernacularIsoCode);
            if (!string.IsNullOrEmpty(options.NationalLanguage1IsoCode) && options.NationalLanguage1IsoCode != options.VernacularIsoCode)
            {
                langs.Add(options.NationalLanguage1IsoCode);
            }
            if (!string.IsNullOrEmpty(options.NationalLanguage2IsoCode))
            {
                langs.Add(options.NationalLanguage2IsoCode);
            }
            book.SetMultilingualContentLanguages(langs.ToArray());

            //we might change this later, or make it optional, but for now, this will prevent surprises to processes
            //running this CLI... the folder name won't change out from under it.
            book.LockDownTheFileAndFolderName = true;

            book.SetLayout(layout);
            book.BringBookUpToDate(new NullProgress());
            Console.WriteLine("Finished Hydrating.");
            Debug.WriteLine("Finished Hydrating.");
            return(0);
        }
        protected Bloom.Book.Book CreateBookWithPhysicalFile(string bookHtml, CollectionSettings collectionSettings)
        {
            _collectionSettings = collectionSettings;
            var fileLocator = new BloomFileLocator(new CollectionSettings(), new XMatterPackFinder(new string[] { }), ProjectContext.GetFactoryFileLocations(),
                                                   ProjectContext.GetFoundFileLocations(), ProjectContext.GetAfterXMatterFileLocations());

            File.WriteAllText(Path.Combine(_tempFolder.Path, "book.htm"), bookHtml);

            var storage = new BookStorage(this._tempFolder.Path, fileLocator, new BookRenamedEvent(), _collectionSettings);

            var b = new Bloom.Book.Book(_metadata, storage, _templateFinder.Object,
                                        _collectionSettings,
                                        _pageSelection.Object, _pageListChangedEvent, new BookRefreshEvent());

            // Some tests need this file early on so it can be copied to the book folder.
            File.WriteAllText(Path.Combine(Path.GetDirectoryName(_tempFolder.Path), "customCollectionStyles.css"), @"/*This is wanted*/");
            return(b);
        }
Beispiel #10
0
        public static int Handle(HydrateParameters options)
        {
            if (!Directory.Exists(options.Path))
            {
                if (options.Path.Contains(".htm"))
                {
                    Debug.WriteLine("Supply only the directory, not the path to the file.");
                    Console.Error.WriteLine("Supply only the directory, not the path to the file.");
                }
                else
                {
                    Debug.WriteLine("Could not find " + options.Path);
                    Console.Error.WriteLine("Could not find " + options.Path);
                }
                return(1);
            }
            Console.WriteLine("Starting Hydrating.");

            var layout = new Layout
            {
                SizeAndOrientation = SizeAndOrientation.FromString(options.SizeAndOrientation)
            };

            var collectionSettings = new CollectionSettings
            {
                XMatterPackName     = options.XMatter,
                Language1Iso639Code = options.VernacularIsoCode,
                Language2Iso639Code = string.IsNullOrWhiteSpace(options.NationalLanguage1IsoCode) ? options.VernacularIsoCode : options.NationalLanguage1IsoCode,
                Language3Iso639Code = options.NationalLanguage2IsoCode
            };

            XMatterPackFinder xmatterFinder = new XMatterPackFinder(new[] { BloomFileLocator.GetInstalledXMatterDirectory() });
            var locator = new BloomFileLocator(collectionSettings, xmatterFinder, ProjectContext.GetFactoryFileLocations(),
                                               ProjectContext.GetFoundFileLocations(), ProjectContext.GetAfterXMatterFileLocations());

            var bookInfo = new BookInfo(options.Path, true);
            var book     = new Book.Book(bookInfo, new BookStorage(options.Path, locator, new BookRenamedEvent(), collectionSettings),
                                         null, collectionSettings, null, null, new BookRefreshEvent(), new BookSavedEvent());

            //we might change this later, or make it optional, but for now, this will prevent surprises to processes
            //running this CLI... the folder name won't change out from under it.
            book.LockDownTheFileAndFolderName = true;

            book.SetLayout(layout);
            book.BringBookUpToDate(new NullProgress());
            Console.WriteLine("Finished Hydrating.");
            Debug.WriteLine("Finished Hydrating.");
            return(0);
        }
        protected Bloom.Book.Book CreateBookWithPhysicalFile(string bookHtml, CollectionSettings collectionSettings)
        {
            _collectionSettings = collectionSettings;
            var fileLocator = new BloomFileLocator(new CollectionSettings(), new XMatterPackFinder(new string[] { }), ProjectContext.GetFactoryFileLocations(),
                                                   ProjectContext.GetFoundFileLocations(), ProjectContext.GetAfterXMatterFileLocations());

            File.WriteAllText(Path.Combine(_tempFolder.Path, "book.htm"), bookHtml);

            var storage = new BookStorage(this._tempFolder.Path, fileLocator, new BookRenamedEvent(), _collectionSettings);

            var b = new Bloom.Book.Book(_metadata, storage, _templateFinder.Object,
                                        _collectionSettings,
                                        _pageSelection.Object, _pageListChangedEvent, new BookRefreshEvent());

            return(b);
        }
 private static BloomFileLocator GetTestFileLocator()
 {
     return(new BloomFileLocator(s_collectionSettings, new XMatterPackFinder(new[] { BloomFileLocator.GetInstalledXMatterDirectory() }), ProjectContext.GetFactoryFileLocations(),
                                 ProjectContext.GetFoundFileLocations(), ProjectContext.GetAfterXMatterFileLocations()));
 }
Beispiel #13
0
        public void OneTimeSetup()
        {
            _testFolder = new TemporaryFolder("SpreadsheetImporterWithBookTests");
            // We need 2 layers of temp folder because BringBookUpToDate will change the name of the book
            // folder to match an imported title.
            _bookFolder = new TemporaryFolder(_testFolder, "Book");
            var settings = new NewCollectionSettings();

            settings.Language1.Iso639Code = "en";
            settings.Language1.SetName("English", false);
            settings.SettingsFilePath = Path.Combine(_bookFolder.FolderPath, "dummy");

            var fileLocator = new BloomFileLocator(settings, new XMatterPackFinder(new string[] { }), ProjectContext.GetFactoryFileLocations(),
                                                   ProjectContext.GetFoundFileLocations(), ProjectContext.GetAfterXMatterFileLocations());
            var bookFilePath = Path.Combine(_bookFolder.FolderPath, "testBook.htm");

            if (File.Exists(bookFilePath))             // Shouldn't ever happen, but... just being careful.
            {
                RobustFile.Delete(bookFilePath);
            }
            _dom = SetupTestDom();
            // Write out our test book
            File.WriteAllText(bookFilePath, _dom.RawDom.OuterXml.ToString());
            var storage = new BookStorage(_bookFolder.FolderPath, fileLocator, new BookRenamedEvent(), settings);

            var book = new Bloom.Book.Book(new BookInfo(_bookFolder.FolderPath, true), storage, null,
                                           settings, new Bloom.Edit.PageSelection(),
                                           new PageListChangedEvent(), new BookRefreshEvent());

            // Create the regular production importer
            _importer = new SpreadsheetImporter(null, book, _bookFolder.FolderPath);

            // Set up the internal spreadsheet rows directly.
            var ss             = new InternalSpreadsheet();
            var columnForEn    = ss.AddColumnForLang("en", "English");
            var columnForImage = ss.GetColumnForTag(InternalSpreadsheet.ImageSourceColumnLabel);

            var newTitle = "My new book title";
            var titleRow = new ContentRow(ss);

            titleRow.AddCell(InternalSpreadsheet.BookTitleRowLabel);
            titleRow.SetCell(columnForEn, newTitle);

            var coverImageRow = new ContentRow(ss);

            coverImageRow.AddCell(InternalSpreadsheet.CoverImageRowLabel);
            coverImageRow.SetCell(columnForImage, Path.Combine("images", "Othello 199.jpg"));

            _importer.Import(ss);

            _resultElement = ReadResultingBookToXml(newTitle);
        }
        public static void ChangeLayoutForAllContentPagesInAllBooks(IProgress progress, string collectionPath, string bookPath, string pageGuid)
        {
            if (!File.Exists(bookPath))
            {
                MessageBox.Show("Could not find template book " + bookPath);
                return;
            }
            if (!File.Exists(collectionPath))
            {
                MessageBox.Show("Could not find collection file " + collectionPath);
                return;
            }
            var collectionFolder = Path.GetDirectoryName(collectionPath);

            if (File.Exists(TeamCollectionManager.GetTcLinkPathFromLcPath(collectionFolder)))
            {
                MessageBox.Show("Change Layout command cannot currently be used in Team Collections");
                return;
                // To make this possible, we'd need to spin up a TeamCollectionManager and TeamCollection and pass the latter
                // to the Book as its SaveContext and still changes would be forbidden unless every book was checked out.
            }

            var problems                    = new StringBuilder();
            var collection                  = new BookCollection(collectionFolder, BookCollection.CollectionType.TheOneEditableCollection, new BookSelection(), null);
            var collectionSettings          = new CollectionSettings(collectionPath);
            XMatterPackFinder xmatterFinder = new XMatterPackFinder(new[]
            {
                BloomFileLocator.GetFactoryXMatterDirectory()
            });
            var locator = new BloomFileLocator(collectionSettings, xmatterFinder, ProjectContext.GetFactoryFileLocations(),
                                               ProjectContext.GetFoundFileLocations(), ProjectContext.GetAfterXMatterFileLocations());

            // AlwaysSaveable is fine here, as we checked above that it's not a TC.
            var templateBookInfo = new BookInfo(Path.GetDirectoryName(bookPath), true, new AlwaysEditSaveContext());
            var templateBook     = new Book.Book(templateBookInfo, new BookStorage(templateBookInfo.FolderPath, locator, new BookRenamedEvent(), collectionSettings),
                                                 null, collectionSettings, null, null, new BookRefreshEvent(), new BookSavedEvent(), new NoEditSaveContext());

            var   pageDictionary = templateBook.GetTemplatePagesIdDictionary();
            IPage page           = null;

            if (!pageDictionary.TryGetValue(pageGuid, out page))
            {
                MessageBox.Show("Could not find template page " + pageGuid);
                return;
            }

            int i = 0;

            foreach (var bookInfo in collection.GetBookInfos())
            {
                i++;
                try
                {
                    var book = new Book.Book(bookInfo,
                                             new BookStorage(bookInfo.FolderPath, locator, new BookRenamedEvent(), collectionSettings),
                                             null, collectionSettings, null, null, new BookRefreshEvent(), new BookSavedEvent());
                    //progress.WriteMessage("Processing " + book.TitleBestForUserDisplay + " " + i + "/" + collection.GetBookInfos().Count());
                    progress.ProgressIndicator.PercentCompleted = i * 100 / collection.GetBookInfos().Count();

                    book.ChangeLayoutForAllContentPages(page);
                }
                catch (Exception ex)
                {
                    Debug.WriteLine(ex.Message);
                    Console.WriteLine(ex.Message);
                    Console.WriteLine(ex.StackTrace);
                    problems.AppendLine(Path.GetFileName(bookInfo.FolderPath));
                }
            }
            if (problems.Length == 0)
            {
                MessageBox.Show("All books converted successfully");
            }
            else
            {
                MessageBox.Show("Bloom had problems converting the following books; please check them:\n" + problems);
            }
        }