From 60d86bba2f19ae44edc406416a85785916c99463 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Wed, 7 Feb 2018 16:08:08 +0100 Subject: [PATCH 01/94] Update to MADR 1.3.0 --- docs/adr/template.md | 62 ++++++++++++++++++++++++-------------------- 1 file changed, 34 insertions(+), 28 deletions(-) diff --git a/docs/adr/template.md b/docs/adr/template.md index e0433876d5d..e1672a2dc09 100644 --- a/docs/adr/template.md +++ b/docs/adr/template.md @@ -1,42 +1,48 @@ -# *[short title of solved problem and solution]* +# [short title of solved problem and solution] -**User Story:** *[ticket/issue-number]* +User Story: [ticket/issue-number] -*[context and problem statement]* -*[decision drivers | forces]* +[context and problem statement] +[decision drivers | forces | facing] -## Considered Alternatives +## Considered Options -* *[alternative 1]* -* *[alternative 2]* -* *[alternative 3]* -* *[...]* +* [option 1] +* [option 2] +* [option 3] +* ... ## Decision Outcome -* Chosen Alternative: *[alternative 1]* -* *[justification. e.g., only alternative, which meets k.o. criterion decision driver | which resolves force force | ... | comes out best (see below)]* -* *[consequences. e.g., negative impact on quality attribute, follow-up decisions required, ...]* +Chosen option: [option 1], because [justification. e.g., only option, which meets k.o. criterion decision driver | which resolves force force | ... | comes out best (see below)]. -## Pros and Cons of the Alternatives +Positive Consequences: + - [e.g., improvement of quality attribute satisfaction, follow-up decisions required, ...] + - ... -### *[alternative 1]* +Negative consequences: + - [e.g., compromising quality attribute, follow-up decisions required, ...] + - ... -* `+` *[argument 1 pro]* -* `+` *[argument 2 pro]* -* `-` *[argument 1 con]* -* *[...]* +## Pros and Cons of the Options -### *[alternative 2]* +### [option 1] -* `+` *[argument 1 pro]* -* `+` *[argument 2 pro]* -* `-` *[argument 1 con]* -* *[...]* +* Good, because [argument a] +* Good, because [argument b] +* Bad, because [argument c] +* ... -### *[alternative 3]* +### [option 2] -* `+` *[argument 1 pro]* -* `+` *[argument 2 pro]* -* `-` *[argument 1 con]* -* *[...]* +* Good, because [argument a] +* Good, because [argument b] +* Bad, because [argument c] +* ... + +### [option 3] + +* Good, because [argument a] +* Good, because [argument b] +* Bad, because [argument c] +* ... From 427a9aad66443ff3f1f58fcb08906a309d5a36d5 Mon Sep 17 00:00:00 2001 From: Stefan Kolb Date: Wed, 7 Feb 2018 16:13:08 +0100 Subject: [PATCH 02/94] Refactor and fix deletion of files that are not present anymore --- .../gui/fieldeditors/LinkedFileViewModel.java | 47 ++++++++++--------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/src/main/java/org/jabref/gui/fieldeditors/LinkedFileViewModel.java b/src/main/java/org/jabref/gui/fieldeditors/LinkedFileViewModel.java index 664bfefad7e..3070d518944 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/LinkedFileViewModel.java +++ b/src/main/java/org/jabref/gui/fieldeditors/LinkedFileViewModel.java @@ -282,35 +282,36 @@ public void moveToDefaultDirectory() { public boolean delete() { Optional file = linkedFile.findIn(databaseContext, Globals.prefs.getFileDirectoryPreferences()); + + if (!file.isPresent()) { + LOGGER.warn("Could not find file " + linkedFile.getLink()); + return true; + } + ButtonType removeFromEntry = new ButtonType(Localization.lang("Remove from entry"), ButtonData.YES); + ButtonType deleteFromEntry = new ButtonType(Localization.lang("Delete from disk")); + Optional buttonType = dialogService.showCustomButtonDialogAndWait(AlertType.INFORMATION, + Localization.lang("Delete '%0'", file.get().toString()), + Localization.lang("Delete the selected file permanently from disk, or just remove the file from the entry? Pressing Delete will delete the file permanently from disk."), + removeFromEntry, deleteFromEntry, ButtonType.CANCEL); + + if (buttonType.isPresent()) { + if (buttonType.get().equals(removeFromEntry)) { + return true; + } - if (file.isPresent()) { - ButtonType deleteFromEntry = new ButtonType(Localization.lang("Delete from disk")); - Optional buttonType = dialogService.showCustomButtonDialogAndWait(AlertType.INFORMATION, - Localization.lang("Delete '%0'", file.get().toString()), - Localization.lang("Delete the selected file permanently from disk, or just remove the file from the entry? Pressing Delete will delete the file permanently from disk."), - removeFromEntry, deleteFromEntry, ButtonType.CANCEL); + if (buttonType.get().equals(deleteFromEntry)) { - if (buttonType.isPresent()) { - if (buttonType.get().equals(removeFromEntry)) { + try { + Files.delete(file.get()); return true; - } - if (buttonType.get().equals(deleteFromEntry)) { - - try { - Files.delete(file.get()); - return true; - } catch (IOException ex) { - dialogService.showErrorDialogAndWait( - Localization.lang("Cannot delete file"), - Localization.lang("File permission error")); - LOGGER.warn("File permission error while deleting: " + linkedFile, ex); - return false; - } + } catch (IOException ex) { + dialogService.showErrorDialogAndWait( + Localization.lang("Cannot delete file"), + Localization.lang("File permission error")); + LOGGER.warn("File permission error while deleting: " + linkedFile, ex); } } - } else { - LOGGER.warn("Could not find file " + linkedFile.getLink()); } return false; } From 0e15a372be438f4287782bf0289a054efd7ae7ae Mon Sep 17 00:00:00 2001 From: Stefan Kolb Date: Wed, 7 Feb 2018 16:36:46 +0100 Subject: [PATCH 03/94] Fix UI test --- .../org/jabref/gui/fieldeditors/LinkedFileViewModelTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/org/jabref/gui/fieldeditors/LinkedFileViewModelTest.java b/src/test/java/org/jabref/gui/fieldeditors/LinkedFileViewModelTest.java index 1fd2bfcc6d6..b1bfa49ce90 100644 --- a/src/test/java/org/jabref/gui/fieldeditors/LinkedFileViewModelTest.java +++ b/src/test/java/org/jabref/gui/fieldeditors/LinkedFileViewModelTest.java @@ -48,7 +48,7 @@ public void setUp() { } @Test - public void deleteWhenFilePathNotPresentReturnsFalse() { + public void deleteWhenFilePathNotPresentReturnsTrue() { // Making this a spy, so we can inject an empty optional without digging into the implementation linkedFile = spy(new LinkedFile("", "nonexistent file", "")); doReturn(Optional.empty()).when(linkedFile).findIn(any(BibDatabaseContext.class), any(FileDirectoryPreferences.class)); @@ -56,7 +56,7 @@ public void deleteWhenFilePathNotPresentReturnsFalse() { LinkedFileViewModel viewModel = new LinkedFileViewModel(linkedFile, entry, databaseContext, taskExecutor, dialogService); boolean removed = viewModel.delete(); - assertFalse(removed); + assertTrue(removed); verifyZeroInteractions(dialogService); // dialog was never shown } From 9228285befd2b7f1524f7623a092b3b70a373fe5 Mon Sep 17 00:00:00 2001 From: Stefan Kolb Date: Wed, 7 Feb 2018 17:11:52 +0100 Subject: [PATCH 04/94] Fix #3687 Allow unknown file types --- .../java/org/jabref/gui/desktop/JabRefDesktop.java | 2 +- .../externalfiletype/UnknownExternalFileType.java | 3 +++ .../gui/maintable/MainTableSelectionListener.java | 13 +++++++++++-- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/jabref/gui/desktop/JabRefDesktop.java b/src/main/java/org/jabref/gui/desktop/JabRefDesktop.java index c5e1fcf78a2..b256e5e3b76 100644 --- a/src/main/java/org/jabref/gui/desktop/JabRefDesktop.java +++ b/src/main/java/org/jabref/gui/desktop/JabRefDesktop.java @@ -194,7 +194,7 @@ public static boolean openExternalFileUnknown(JabRefFrame frame, BibEntry entry, return false; } else if (answer == JOptionPane.YES_OPTION) { // User wants to define the new file type. Show the dialog: - ExternalFileType newType = new ExternalFileType(fileType.getName(), "", "", "", "new", + ExternalFileType newType = new ExternalFileType(fileType.getName(), fileType.getExtension(), "", "", "new", IconTheme.JabRefIcon.FILE.getSmallIcon()); ExternalFileTypeEntryEditor editor = new ExternalFileTypeEntryEditor(frame, newType); editor.setVisible(true); diff --git a/src/main/java/org/jabref/gui/externalfiletype/UnknownExternalFileType.java b/src/main/java/org/jabref/gui/externalfiletype/UnknownExternalFileType.java index 59e9198887a..e51e011d0b6 100644 --- a/src/main/java/org/jabref/gui/externalfiletype/UnknownExternalFileType.java +++ b/src/main/java/org/jabref/gui/externalfiletype/UnknownExternalFileType.java @@ -13,4 +13,7 @@ public UnknownExternalFileType(String name) { super(name, "", "", "", "unknown", IconTheme.JabRefIcon.FILE.getSmallIcon()); } + public UnknownExternalFileType(String name, String extension) { + super(name, extension, "", "", "unknown", IconTheme.JabRefIcon.FILE.getSmallIcon()); + } } diff --git a/src/main/java/org/jabref/gui/maintable/MainTableSelectionListener.java b/src/main/java/org/jabref/gui/maintable/MainTableSelectionListener.java index d5a1168aa54..b67a0ba2079 100644 --- a/src/main/java/org/jabref/gui/maintable/MainTableSelectionListener.java +++ b/src/main/java/org/jabref/gui/maintable/MainTableSelectionListener.java @@ -30,6 +30,7 @@ import org.jabref.gui.entryeditor.EntryEditor; import org.jabref.gui.externalfiletype.ExternalFileMenuItem; import org.jabref.gui.externalfiletype.ExternalFileType; +import org.jabref.gui.externalfiletype.UnknownExternalFileType; import org.jabref.gui.filelist.FileListEntry; import org.jabref.gui.filelist.FileListTableModel; import org.jabref.gui.menus.RightClickMenu; @@ -38,6 +39,7 @@ import org.jabref.gui.specialfields.SpecialFieldViewModel; import org.jabref.logic.l10n.Localization; import org.jabref.logic.util.OS; +import org.jabref.logic.util.io.FileUtil; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.FieldName; import org.jabref.model.entry.specialfields.SpecialField; @@ -343,9 +345,16 @@ private void showIconRightClickMenu(MouseEvent e, int row, MainTableColumn colum if ((description == null) || (description.trim().isEmpty())) { description = flEntry.getLink(); } + + Optional fileType = flEntry.getType(); + + // file type might be unknown + if (!fileType.isPresent()) { + String fileExtension = FileUtil.getFileExtension(flEntry.getLink()).orElse(""); + fileType = Optional.of(new UnknownExternalFileType(fileExtension.toUpperCase(), fileExtension)); + } menu.add(new ExternalFileMenuItem(panel.frame(), entry, description, flEntry.getLink(), - flEntry.getType().get().getIcon(), panel.getBibDatabaseContext(), - flEntry.getType())); + fileType.get().getIcon(), panel.getBibDatabaseContext(), fileType)); showDefaultPopup = false; } } else { From bcd1870f63c152f5b32a6e51da55354c50304949 Mon Sep 17 00:00:00 2001 From: Joerg Lenhard Date: Wed, 7 Feb 2018 17:50:14 +0100 Subject: [PATCH 05/94] Try to change color of magnifier icon --- src/main/java/org/jabref/gui/IconTheme.java | 1 + .../org/jabref/gui/search/GlobalSearchBar.java | 1 + .../org/jabref/gui/search/SearchTextField.java | 18 +++++++++++++++++- 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/jabref/gui/IconTheme.java b/src/main/java/org/jabref/gui/IconTheme.java index 0b78c7cd09e..ad99a9b6543 100644 --- a/src/main/java/org/jabref/gui/IconTheme.java +++ b/src/main/java/org/jabref/gui/IconTheme.java @@ -198,6 +198,7 @@ public enum JabRefIcon { REFRESH(MaterialDesignIcon.REFRESH), DELETE_ENTRY(MaterialDesignIcon.DELETE), SEARCH(MaterialDesignIcon.MAGNIFY), + ADVANCED_SEARCH(Color.ORANGE, MaterialDesignIcon.MAGNIFY), PREFERENCES(MaterialDesignIcon.SETTINGS), HELP(MaterialDesignIcon.HELP_CIRCLE), UP(MaterialDesignIcon.CHEVRON_UP), diff --git a/src/main/java/org/jabref/gui/search/GlobalSearchBar.java b/src/main/java/org/jabref/gui/search/GlobalSearchBar.java index 4d12cb41cd7..a25a646ed57 100644 --- a/src/main/java/org/jabref/gui/search/GlobalSearchBar.java +++ b/src/main/java/org/jabref/gui/search/GlobalSearchBar.java @@ -391,6 +391,7 @@ public void updateResults(int matched, TextFlow description, boolean grammarBase currentResults.setText(Localization.lang("Found %0 results.", String.valueOf(matched))); searchField.pseudoClassStateChanged(CLASS_RESULTS_FOUND, true); } + SearchTextField.switchSearchColor(searchField, grammarBasedSearch); Tooltip tooltip = new Tooltip(); tooltip.setContentDisplay(ContentDisplay.GRAPHIC_ONLY); tooltip.setGraphic(description); diff --git a/src/main/java/org/jabref/gui/search/SearchTextField.java b/src/main/java/org/jabref/gui/search/SearchTextField.java index e018ac2efd9..e0f9f9f686a 100644 --- a/src/main/java/org/jabref/gui/search/SearchTextField.java +++ b/src/main/java/org/jabref/gui/search/SearchTextField.java @@ -1,8 +1,10 @@ package org.jabref.gui.search; +import javafx.scene.Node; import javafx.scene.control.TextField; import org.jabref.gui.IconTheme; +import org.jabref.gui.util.DefaultTaskExecutor; import org.jabref.logic.l10n.Localization; import org.controlsfx.control.textfield.CustomTextField; @@ -13,7 +15,21 @@ public class SearchTextField { public static TextField create() { CustomTextField textField = (CustomTextField) TextFields.createClearableTextField(); textField.setPromptText(Localization.lang("Search") + "..."); - textField.setLeft(IconTheme.JabRefIcon.SEARCH.getGraphicNode()); + Node node = IconTheme.JabRefIcon.SEARCH.getGraphicNode(); + node.setStyle("-fx-text-fill: #00ffff"); + textField.setLeft(node); return textField; } + + public static void switchSearchColor(TextField textField, boolean grammarBasedSearch) { + if (grammarBasedSearch) { + DefaultTaskExecutor.runInJavaFXThread(() -> + ((CustomTextField) textField).setLeft(IconTheme.JabRefIcon.ADVANCED_SEARCH.getGraphicNode())); + } else { + DefaultTaskExecutor.runInJavaFXThread(() -> + ((CustomTextField) textField).setLeft(IconTheme.JabRefIcon.SEARCH.getGraphicNode())); + } + } + + } From f4ff518ba59128620493d9b7171a945fc8d21243 Mon Sep 17 00:00:00 2001 From: Stefan Kolb Date: Wed, 7 Feb 2018 18:35:09 +0100 Subject: [PATCH 06/94] Escape delimiters #3646 --- src/main/java/org/jabref/logic/exporter/GroupSerializer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jabref/logic/exporter/GroupSerializer.java b/src/main/java/org/jabref/logic/exporter/GroupSerializer.java index e8ce0925c39..8d252dfdc10 100644 --- a/src/main/java/org/jabref/logic/exporter/GroupSerializer.java +++ b/src/main/java/org/jabref/logic/exporter/GroupSerializer.java @@ -171,7 +171,7 @@ private String serializeAutomaticKeywordGroup(AutomaticKeywordGroup group) { appendAutomaticGroupDetails(sb, group); sb.append(StringUtil.quote(group.getField(), MetadataSerializationConfiguration.GROUP_UNIT_SEPARATOR, MetadataSerializationConfiguration.GROUP_QUOTE_CHAR)); sb.append(MetadataSerializationConfiguration.GROUP_UNIT_SEPARATOR); - sb.append(group.getKeywordDelimiter()); + sb.append(StringUtil.quote(group.getKeywordDelimiter().toString(), MetadataSerializationConfiguration.GROUP_UNIT_SEPARATOR, MetadataSerializationConfiguration.GROUP_QUOTE_CHAR)); sb.append(MetadataSerializationConfiguration.GROUP_UNIT_SEPARATOR); sb.append(group.getKeywordHierarchicalDelimiter()); sb.append(MetadataSerializationConfiguration.GROUP_UNIT_SEPARATOR); From 798a7d25fcc5f0353d0a51eeb447402675ea2682 Mon Sep 17 00:00:00 2001 From: Stefan Kolb Date: Wed, 7 Feb 2018 18:46:48 +0100 Subject: [PATCH 07/94] Add test --- .../org/jabref/logic/importer/util/GroupsParserTest.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/test/java/org/jabref/logic/importer/util/GroupsParserTest.java b/src/test/java/org/jabref/logic/importer/util/GroupsParserTest.java index ef694fac9fa..b5ef64a41c3 100644 --- a/src/test/java/org/jabref/logic/importer/util/GroupsParserTest.java +++ b/src/test/java/org/jabref/logic/importer/util/GroupsParserTest.java @@ -42,6 +42,13 @@ public void fromStringParsesExplicitGroupWithEscapedCharacterInName() throws Exc assertEquals(expected, parsed); } + @Test + public void DelimiterThatNeedsToBeEscaped() throws Exception { + AutomaticGroup expected = new AutomaticKeywordGroup("group1", GroupHierarchyType.INDEPENDENT, "keywords", ';', '>'); + AbstractGroup parsed = GroupsParser.fromString("AutomaticKeywordGroup:group1;0;keywords;\\;;>;1;;;;;", ';', fileMonitor); + assertEquals(expected, parsed); + } + @Test(expected = ParseException.class) public void fromStringThrowsParseExceptionForNotEscapedGroupName() throws Exception { GroupsParser.fromString("ExplicitGroup:slit\\\\;0\\;mertsch_slit2_2007\\;;", ',', fileMonitor); From f6955027d35d5b9f2014b1b00cc73bbaf230bbc4 Mon Sep 17 00:00:00 2001 From: Stefan Kolb Date: Wed, 7 Feb 2018 18:50:26 +0100 Subject: [PATCH 08/94] Also escape hierarchical delimiter --- src/main/java/org/jabref/logic/exporter/GroupSerializer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jabref/logic/exporter/GroupSerializer.java b/src/main/java/org/jabref/logic/exporter/GroupSerializer.java index 8d252dfdc10..eed98ed454c 100644 --- a/src/main/java/org/jabref/logic/exporter/GroupSerializer.java +++ b/src/main/java/org/jabref/logic/exporter/GroupSerializer.java @@ -173,7 +173,7 @@ private String serializeAutomaticKeywordGroup(AutomaticKeywordGroup group) { sb.append(MetadataSerializationConfiguration.GROUP_UNIT_SEPARATOR); sb.append(StringUtil.quote(group.getKeywordDelimiter().toString(), MetadataSerializationConfiguration.GROUP_UNIT_SEPARATOR, MetadataSerializationConfiguration.GROUP_QUOTE_CHAR)); sb.append(MetadataSerializationConfiguration.GROUP_UNIT_SEPARATOR); - sb.append(group.getKeywordHierarchicalDelimiter()); + sb.append(StringUtil.quote(group.getKeywordHierarchicalDelimiter().toString(), MetadataSerializationConfiguration.GROUP_UNIT_SEPARATOR, MetadataSerializationConfiguration.GROUP_QUOTE_CHAR)); sb.append(MetadataSerializationConfiguration.GROUP_UNIT_SEPARATOR); appendGroupDetails(sb, group); return sb.toString(); From b9bfea97a6a451ea6a79601a5e5bd8ca881d493a Mon Sep 17 00:00:00 2001 From: Stefan Kolb Date: Wed, 7 Feb 2018 18:52:02 +0100 Subject: [PATCH 09/94] Add test for hierarchical delimiter escaping --- .../org/jabref/logic/importer/util/GroupsParserTest.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/test/java/org/jabref/logic/importer/util/GroupsParserTest.java b/src/test/java/org/jabref/logic/importer/util/GroupsParserTest.java index b5ef64a41c3..dd9385a736a 100644 --- a/src/test/java/org/jabref/logic/importer/util/GroupsParserTest.java +++ b/src/test/java/org/jabref/logic/importer/util/GroupsParserTest.java @@ -43,12 +43,19 @@ public void fromStringParsesExplicitGroupWithEscapedCharacterInName() throws Exc } @Test - public void DelimiterThatNeedsToBeEscaped() throws Exception { + public void KeywordDelimiterThatNeedsToBeEscaped() throws Exception { AutomaticGroup expected = new AutomaticKeywordGroup("group1", GroupHierarchyType.INDEPENDENT, "keywords", ';', '>'); AbstractGroup parsed = GroupsParser.fromString("AutomaticKeywordGroup:group1;0;keywords;\\;;>;1;;;;;", ';', fileMonitor); assertEquals(expected, parsed); } + @Test + public void HierarchicalDelimiterThatNeedsToBeEscaped() throws Exception { + AutomaticGroup expected = new AutomaticKeywordGroup("group1", GroupHierarchyType.INDEPENDENT, "keywords", ',', ';'); + AbstractGroup parsed = GroupsParser.fromString("AutomaticKeywordGroup:group1;0;keywords;,;\\;;1;;;;;", ';', fileMonitor); + assertEquals(expected, parsed); + } + @Test(expected = ParseException.class) public void fromStringThrowsParseExceptionForNotEscapedGroupName() throws Exception { GroupsParser.fromString("ExplicitGroup:slit\\\\;0\\;mertsch_slit2_2007\\;;", ',', fileMonitor); From 83a6557ef090f6c0cf7fc74f5c5a5f4ecc697abb Mon Sep 17 00:00:00 2001 From: Siedlerchr Date: Thu, 8 Feb 2018 00:25:56 +0100 Subject: [PATCH 10/94] migrate majority of tests to junit5 please check if I didn't forgot one Test annotation --- .../LastFocusedTabPreferencesTest.java | 0 src/test/java/org/jabref/CodeStyleTests.java | 9 +- .../SearchQueryHighlightListenerTest.java | 113 ------ .../java/org/jabref/TestIconsProperties.java | 16 +- .../architecture/MainArchitectureTests.java | 2 +- .../cleanup/CleanupActionsListModelTest.java | 4 +- .../org/jabref/cli/AuxCommandLineTest.java | 13 +- .../java/org/jabref/cli/JabRefCLITest.java | 28 +- .../BibEntrySuggestionProviderTest.java | 31 +- .../DefaultAutoCompleterTest.java | 40 +-- .../FieldValueSuggestionProviderTest.java | 38 +- .../PersonNameSuggestionProviderTest.java | 43 ++- .../ExternalFileTypeTest.java | 11 +- .../fieldeditors/HtmlTransferableTest.java | 4 +- .../IdentifierEditorViewModelTest.java | 6 +- .../gui/groups/GroupNodeViewModelTest.java | 10 +- .../gui/groups/GroupTreeViewModelTest.java | 10 +- .../EntryFromFileCreatorManagerTest.java | 30 +- .../gui/importer/EntryFromPDFCreatorTest.java | 32 +- .../fetcher/OAI2HandlerFetcherTest.java | 100 +++--- ...sAndRegexBasedSearchRuleDescriberTest.java | 4 +- .../GrammarBasedSearchRuleDescriberTest.java | 4 +- .../gui/util/RecursiveTreeItemTest.java | 6 +- .../jabref/gui/util/TooltipTextUtilTest.java | 41 +-- .../CitationStyleToClipboardWorkerTest.java | 18 +- .../org/jabref/logic/TypedBibEntryTest.java | 17 +- .../autosaveandbackup/BackupManagerTest.java | 7 +- .../jabref/logic/auxparser/AuxParserTest.java | 2 +- .../logic/bibtex/FieldContentParserTest.java | 8 +- .../bibtex/LatexFieldFormatterTests.java | 15 +- .../comparator/BibDatabaseDiffTest.java | 5 +- .../BibtexStringComparatorTest.java | 6 +- .../CrossRefEntryComparatorTest.java | 12 +- .../comparator/EntryComparatorTest.java | 2 +- .../comparator/FieldComparatorTest.java | 4 +- .../bibtex/comparator/MetaDataDiffTest.java | 4 +- .../BibtexKeyGeneratorTest.java | 36 +- .../MakeLabelWithDatabaseTest.java | 6 +- .../MakeLabelWithoutDatabaseTest.java | 6 +- .../logic/bst/BibtexCaseChangersTest.java | 11 +- .../logic/bst/BibtexNameFormatterTest.java | 64 ++-- .../jabref/logic/bst/BibtexPurifyTest.java | 9 +- .../org/jabref/logic/bst/BibtexWidthTest.java | 15 +- .../java/org/jabref/logic/bst/TestVM.java | 325 +++++++++--------- .../logic/bst/TextPrefixFunctionTest.java | 9 +- .../CitationStyleGeneratorTest.java | 2 +- .../citationstyle/CitationStyleTest.java | 9 +- .../cleanup/ConvertToBiblatexCleanupTest.java | 25 +- .../cleanup/ConvertToBibtexCleanupTest.java | 23 +- .../cleanup/FieldFormatterCleanupTest.java | 35 +- .../jabref/logic/cleanup/ISSNCleanupTest.java | 15 +- .../exporter/BibtexDatabaseWriterTest.java | 21 +- .../exporter/FieldFormatterCleanupsTest.java | 6 +- .../logic/exporter/GroupSerializerTest.java | 6 +- .../exporter/MetaDataSerializerTest.java | 6 +- .../formatter/IdentityFormatterTest.java | 8 +- .../bibtexfields/ClearFormatterTest.java | 11 +- .../EscapeUnderscoresFormatterTest.java | 9 +- .../HtmlToLatexFormatterTest.java | 8 +- .../HtmlToUnicodeFormatterTest.java | 8 +- .../LatexCleanupFormatterTest.java | 8 +- .../NormalizeDateFormatterTest.java | 57 +-- .../NormalizeMonthFormatterTest.java | 11 +- .../NormalizeNamesFormatterTest.java | 8 +- .../NormalizePagesFormatterTest.java | 45 +-- .../OrdinalsToSuperscriptFormatterTest.java | 8 +- .../RemoveBracesFormatterTest.java | 9 +- ...RemoveHyphenatedNewlinesFormatterTest.java | 8 +- .../RemoveNewlinesFormatterTest.java | 10 +- .../bibtexfields/UnicodeConverterTest.java | 9 +- .../UnicodeToLatexFormatterTest.java | 8 +- .../UnitsToLatexFormatterTest.java | 9 +- .../casechanger/CapitalizeFormatterTest.java | 17 +- .../casechanger/LowerCaseFormatterTest.java | 13 +- .../ProtectTermsFormatterTest.java | 9 +- .../SentenceCaseFormatterTest.java | 18 +- .../casechanger/TitleCaseFormatterTest.java | 41 +-- .../casechanger/UpperCaseFormatterTest.java | 19 +- .../minifier/MinifyNameListFormatterTest.java | 12 +- .../org/jabref/logic/help/HelpFileTest.java | 6 +- .../importer/BibDatabaseTestsWithFiles.java | 6 +- .../importer/DatabaseFileLookupTest.java | 17 +- .../jabref/logic/importer/ImportDataTest.java | 22 +- .../ImportFormatReaderTestParameterless.java | 31 +- .../logic/importer/OpenDatabaseTest.java | 38 +- .../util/ConvertLegacyExplicitGroupsTest.java | 8 +- .../logic/importer/util/GroupsParserTest.java | 15 +- .../importer/util/JSONEntryParserTest.java | 31 +- .../logic/integrity/BracesCorrectorTest.java | 5 +- .../logic/integrity/EntryLinkCheckerTest.java | 16 +- .../integrity/NoBibTexFieldCheckerTest.java | 6 +- .../integrity/PersonNamesCheckerTest.java | 8 +- .../logic/journals/AbbreviationTest.java | 8 +- .../JournalAbbreviationRepositoryTest.java | 9 +- ...ippedJournalAbbreviationDuplicateTest.java | 25 +- .../org/jabref/logic/l10n/EncodingsTest.java | 6 +- .../org/jabref/logic/l10n/LanguagesTest.java | 10 +- .../l10n/LocalizationConsistencyTest.java | 80 ++--- .../logic/l10n/LocalizationKeyParamsTest.java | 8 +- .../logic/l10n/LocalizationKeyTest.java | 2 +- .../logic/l10n/LocalizationParserTest.java | 4 +- .../jabref/logic/l10n/LocalizationTest.java | 10 +- .../PropertiesLocaleCompletenessTest.java | 4 +- .../jabref/logic/layout/LayoutEntryTest.java | 44 +-- .../org/jabref/logic/layout/LayoutTest.java | 29 +- .../layout/format/AuthorAbbreviatorTest.java | 12 +- .../AuthorAndToSemicolonReplacerTest.java | 6 +- .../format/AuthorAndsCommaReplacerTest.java | 12 +- .../layout/format/AuthorAndsReplacerTest.java | 14 +- .../format/AuthorFirstAbbrLastCommasTest.java | 14 +- .../AuthorFirstAbbrLastOxfordCommasTest.java | 14 +- .../format/AuthorFirstFirstCommasTest.java | 6 +- .../layout/format/AuthorFirstFirstTest.java | 6 +- .../format/AuthorFirstLastCommasTest.java | 14 +- .../AuthorFirstLastOxfordCommasTest.java | 14 +- .../layout/format/AuthorLF_FFAbbrTest.java | 6 +- .../logic/layout/format/AuthorLF_FFTest.java | 6 +- .../format/AuthorLastFirstAbbrCommasTest.java | 14 +- .../AuthorLastFirstAbbrOxfordCommasTest.java | 14 +- .../AuthorLastFirstAbbreviatorTester.java | 20 +- .../format/AuthorLastFirstCommasTest.java | 14 +- .../AuthorLastFirstOxfordCommasTest.java | 14 +- .../layout/format/AuthorLastFirstTest.java | 14 +- .../logic/layout/format/AuthorNatBibTest.java | 8 +- .../logic/layout/format/AuthorOrgSciTest.java | 16 +- .../logic/layout/format/AuthorsTest.java | 42 +-- .../layout/format/CompositeFormatTest.java | 12 +- .../logic/layout/format/DOICheckTest.java | 24 +- .../logic/layout/format/DOIStripTest.java | 14 +- .../layout/format/DateFormatterTest.java | 12 +- .../logic/layout/format/DefaultTest.java | 16 +- .../layout/format/EntryTypeFormatterTest.java | 8 +- .../logic/layout/format/FileLinkTest.java | 8 +- .../logic/layout/format/FirstPageTest.java | 14 +- .../logic/layout/format/HTMLCharsTest.java | 8 +- .../layout/format/HTMLParagraphsTest.java | 14 +- .../logic/layout/format/IfPluralTest.java | 16 +- .../logic/layout/format/LastPageTest.java | 16 +- .../format/LatexToUnicodeFormatterTest.java | 4 +- .../layout/format/NameFormatterTest.java | 28 +- .../NoSpaceBetweenAbbreviationsTest.java | 14 +- .../logic/layout/format/OrdinalTest.java | 6 +- .../logic/layout/format/RTFCharsTest.java | 210 +++++------ .../format/RemoveBracketsAddCommaTest.java | 8 +- .../layout/format/RemoveBracketsTest.java | 8 +- .../logic/layout/format/RemoveTildeTest.java | 24 +- .../layout/format/RemoveWhitespaceTest.java | 6 +- .../logic/layout/format/ReplaceTest.java | 16 +- .../logic/layout/format/RisKeywordsTest.java | 4 +- .../logic/layout/format/RisMonthTest.java | 4 +- .../logic/layout/format/ToLowerCaseTest.java | 6 +- .../logic/layout/format/ToUpperCaseTest.java | 6 +- .../logic/layout/format/WrapContentTest.java | 20 +- .../layout/format/WrapFileLinksTest.java | 15 +- .../jabref/logic/msbib/MsBibAuthorTest.java | 4 +- .../org/jabref/logic/net/URLDownloadTest.java | 25 +- .../org/jabref/logic/net/URLUtilTest.java | 74 ++-- .../logic/openoffice/CitationEntryTest.java | 8 +- .../logic/openoffice/OOBibStyleTest.java | 14 +- .../logic/openoffice/OOPreFormatterTest.java | 4 +- .../logic/openoffice/StyleLoaderTest.java | 33 +- .../pdf/EntryAnnotationImporterTest.java | 12 +- .../logic/pdf/PdfAnnotationImporterTest.java | 5 +- .../logic/remote/RemotePreferencesTest.java | 11 +- .../jabref/logic/remote/RemoteUtilTest.java | 19 +- .../jabref/logic/search/SearchQueryTest.java | 9 +- .../specialfields/SpecialFieldsUtilsTest.java | 9 +- .../logic/util/BracketedPatternTest.java | 20 +- .../org/jabref/logic/util/BuildInfoTest.java | 8 +- .../logic/util/DevelopmentStageTest.java | 7 +- .../org/jabref/logic/util/FileTypeTest.java | 4 +- .../jabref/logic/util/JavaVersionTest.java | 31 +- .../jabref/logic/util/UpdateFieldTest.java | 14 +- .../org/jabref/logic/util/VersionTest.java | 8 +- .../jabref/logic/util/io/FileHistoryTest.java | 4 +- .../logic/util/io/FileNameCleanerTest.java | 21 +- .../util/io/RegExpBasedFileFinderTests.java | 12 +- .../util/strings/DiffHighlightingTest.java | 12 +- .../strings/StringLengthComparatorTest.java | 5 +- .../jabref/logic/xmp/XMPSchemaBibtexTest.java | 120 +++---- .../migrations/PreferencesMigrationsTest.java | 8 +- .../jabref/model/BibDatabaseContextTest.java | 4 +- .../database/BibDatabaseContextTest.java | 8 +- .../BibDatabaseModeDetectionTest.java | 4 +- .../database/DuplicationCheckerTest.java | 9 +- .../model/database/KeyChangeListenerTest.java | 8 +- .../database/event/AutosaveEventTest.java | 2 +- .../org/jabref/model/entry/AuthorTest.java | 4 +- .../model/entry/BibEntryEqualityTest.java | 6 +- .../org/jabref/model/entry/BibEntryTest.java | 19 +- .../org/jabref/model/entry/BibEntryTests.java | 104 +++--- .../jabref/model/entry/BibtexStringTest.java | 9 +- .../model/entry/CanonicalBibEntryTest.java | 9 +- .../java/org/jabref/model/entry/DateTest.java | 8 +- .../jabref/model/entry/EntryLinkListTest.java | 13 +- .../org/jabref/model/entry/FieldNameTest.java | 3 +- .../model/entry/FileFieldBibEntryTest.java | 8 +- .../model/entry/FileFieldWriterTest.java | 6 +- .../model/entry/IEEETranEntryTypesTest.java | 7 +- .../jabref/model/entry/IdGeneratorTest.java | 7 +- .../jabref/model/entry/KeywordListTest.java | 4 +- .../org/jabref/model/entry/KeywordTest.java | 2 +- .../org/jabref/model/entry/MonthTest.java | 135 ++++---- .../entry/identifier/ArXivIdentifierTest.java | 4 +- .../model/entry/identifier/DOITest.java | 98 +++--- .../model/entry/identifier/EprintTest.java | 32 +- .../model/entry/identifier/ISBNTest.java | 7 +- .../model/entry/identifier/ISSNTest.java | 8 +- .../entry/identifier/MathSciNetIdTest.java | 4 +- .../entry/specialfields/SpecialFieldTest.java | 8 +- .../groups/AutomaticKeywordGroupTest.java | 4 +- .../model/groups/ExplicitGroupTest.java | 18 +- .../model/groups/GroupTreeNodeTest.java | 12 +- .../jabref/model/groups/SearchGroupTest.java | 4 +- .../org/jabref/model/groups/TexGroupTest.java | 6 +- .../model/groups/WordKeywordGroupTest.java | 12 +- .../jabref/model/metadata/MetaDataTest.java | 8 +- .../jabref/model/pdf/FileAnnotationTest.java | 6 +- .../search/matchers/MatcherSetsTest.java | 6 +- .../rules/ContainBasedSearchRuleTest.java | 29 +- .../search/rules/SentenceAnalyzerTest.java | 4 +- .../jabref/model/strings/StringUtilTest.java | 8 +- .../jabref/testutils/category/GUITest.java | 15 +- 223 files changed, 2006 insertions(+), 2123 deletions(-) rename src/{test => jmh}/java/org/jabref/preferences/LastFocusedTabPreferencesTest.java (100%) delete mode 100644 src/test/java/org/jabref/SearchQueryHighlightListenerTest.java diff --git a/src/test/java/org/jabref/preferences/LastFocusedTabPreferencesTest.java b/src/jmh/java/org/jabref/preferences/LastFocusedTabPreferencesTest.java similarity index 100% rename from src/test/java/org/jabref/preferences/LastFocusedTabPreferencesTest.java rename to src/jmh/java/org/jabref/preferences/LastFocusedTabPreferencesTest.java diff --git a/src/test/java/org/jabref/CodeStyleTests.java b/src/test/java/org/jabref/CodeStyleTests.java index ec6a5641437..68aead142d6 100644 --- a/src/test/java/org/jabref/CodeStyleTests.java +++ b/src/test/java/org/jabref/CodeStyleTests.java @@ -7,8 +7,9 @@ import org.jabref.model.strings.StringUtil; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertTrue; public class CodeStyleTests { @@ -17,8 +18,8 @@ public void StringUtilClassIsSmall() throws Exception { Path path = Paths.get("src", "main", "java", StringUtil.class.getName().replace('.', '/') + ".java"); int lineCount = Files.readAllLines(path, StandardCharsets.UTF_8).size(); - Assert.assertTrue("StringUtil increased in size. " + assertTrue(lineCount <= 722, () -> "StringUtil increased in size. " + "We try to keep this class as small as possible. " - + "Thus think twice if you add something to StringUtil.", lineCount <= 722); + + "Thus think twice if you add something to StringUtil."); } } diff --git a/src/test/java/org/jabref/SearchQueryHighlightListenerTest.java b/src/test/java/org/jabref/SearchQueryHighlightListenerTest.java deleted file mode 100644 index c1b912517fd..00000000000 --- a/src/test/java/org/jabref/SearchQueryHighlightListenerTest.java +++ /dev/null @@ -1,113 +0,0 @@ -package org.jabref; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.runners.MockitoJUnitRunner; - -import static org.junit.Assert.assertTrue; - -@RunWith(MockitoJUnitRunner.class) -public class SearchQueryHighlightListenerTest { - - //@Mock - //private ProtectedTermsLoader loader; - - - @Before - public void setUp() { - //Globals.prefs = JabRefPreferences.getInstance(); - //Globals.protectedTermsLoader = loader; - //when(loader.getProtectedTermsLists()).thenReturn(Collections.emptyList()); - } - - @Test - public void dummyTest() { - assertTrue(true); - } - - /* - // TODO: Reenable these tests and remove dummyTest - @Test - public void testHighlighting() { - - String content = "Test Word Content"; - String contentToHighlight1 = "Word"; - String contentToHighlight2 = "Content"; - - TextArea ta = new TextArea("", content); - - Highlighter highlighter = ta.getHighlighter(); - Highlight[] highlight = highlighter.getHighlights(); - - //there is no area to highlight! - Assert.assertEquals("Expected no highlighting area ", 0, highlight.length); - - ta.highlightPattern(Optional.of(Pattern.compile("Word"))); - - highlighter = ta.getHighlighter(); - highlight = highlighter.getHighlights(); - - //there is one area to highlight! - Assert.assertEquals("Expected one highlighting area ", 1, highlight.length); - //start of ... Word - Assert.assertEquals(content.indexOf(contentToHighlight1), highlight[0].getStartOffset()); - - //end of ... word - Assert.assertEquals(content.indexOf(contentToHighlight1) + contentToHighlight1.length(), - highlight[0].getEndOffset()); - - //add another word "content" and refresh highlighting - ta.highlightPattern(Optional.of(Pattern.compile("(Word|Content)"))); - highlighter = ta.getHighlighter(); - highlight = highlighter.getHighlights(); - - //there are two areas to highlight! - Assert.assertEquals("Expected two highlighting areas ", 2, highlight.length); - - //start of ... content - Assert.assertEquals(content.indexOf(contentToHighlight2), highlight[1].getStartOffset()); - - //end of ... content - Assert.assertEquals(content.indexOf(contentToHighlight2) + contentToHighlight2.length(), - highlight[1].getEndOffset()); - - //remove everything and check if highlighting is vanished - ta.highlightPattern(Optional.empty()); - highlighter = ta.getHighlighter(); - highlight = highlighter.getHighlights(); - - //there should be none areas to highlight! - Assert.assertEquals("Expected no highlighting area ", 0, highlight.length); - } - - @Test - public void testHighlightingContentIndependence() { - String content = "Test Word Content"; - TextArea ta = new TextArea("", content); - String textOne = ta.getText(); - - ta.highlightPattern(Optional.of((Pattern.compile("Word")))); - - String textTwo = ta.getText(); - Assert.assertEquals("Highlighting may not change content", textOne, textTwo); - - //set up empty arraylist and inform the fieldtextarea - ta.highlightPattern(Optional.empty()); - - String textThree = ta.getText(); - Assert.assertEquals("Highlighting may not change content", textOne, textThree); - } - - @Test - public void testHighlightingInvalidParameter() { - String content = "Test Word Content"; - - TextArea ta = new TextArea("", content); - - //should not matter at all - ta.highlightPattern(null); - } - - */ -} diff --git a/src/test/java/org/jabref/TestIconsProperties.java b/src/test/java/org/jabref/TestIconsProperties.java index 8665822aead..1b54c3f7dd2 100644 --- a/src/test/java/org/jabref/TestIconsProperties.java +++ b/src/test/java/org/jabref/TestIconsProperties.java @@ -12,11 +12,11 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; public class TestIconsProperties { @@ -31,15 +31,14 @@ public void testExistenceOfIconImagesReferencedFromIconsProperties() throws IOEx try (Reader reader = Files.newBufferedReader(Paths.get(iconsPropertiesPath))) { properties.load(reader); } - assertFalse("There must be loaded properties after loading " + iconsPropertiesPath, - properties.entrySet().isEmpty()); + assertFalse(properties.entrySet().isEmpty(), () -> "There must be loaded properties after loading " + iconsPropertiesPath); // check that each key references an existing file for (Map.Entry entry : properties.entrySet()) { String name = entry.getKey().toString(); String value = entry.getValue().toString(); - assertTrue("Referenced image (" + name + " --> " + value + " does not exist in folder " + folder, Files.exists(Paths.get(folder, value))); + assertTrue(Files.exists(Paths.get(folder, value)), () -> "Referenced image (" + name + " --> " + value + " does not exist in folder " + folder); } // check that each image in the folder is referenced by a key @@ -51,8 +50,7 @@ public void testExistenceOfIconImagesReferencedFromIconsProperties() throws IOEx try (Stream pathStream = Files.list(Paths.get(folder))) { List fileNamesInFolder = pathStream.map(p -> p.getFileName().toString()).collect(Collectors.toList()); fileNamesInFolder.removeAll(imagesReferencedFromProperties); - - assertEquals("Images are in the folder that are unused", "[red.png]", fileNamesInFolder.toString()); + assertEquals("[red.png]", fileNamesInFolder.toString(), "Images are in the folder that are unused"); } } } diff --git a/src/test/java/org/jabref/architecture/MainArchitectureTests.java b/src/test/java/org/jabref/architecture/MainArchitectureTests.java index 486c47572ef..50b29c1ea69 100644 --- a/src/test/java/org/jabref/architecture/MainArchitectureTests.java +++ b/src/test/java/org/jabref/architecture/MainArchitectureTests.java @@ -37,7 +37,7 @@ public class MainArchitectureTests { private final String firstPackage; private final String secondPackage; - private Map> exceptions; + private final Map> exceptions; public MainArchitectureTests(String firstPackage, String secondPackage) { this.firstPackage = firstPackage; diff --git a/src/test/java/org/jabref/cleanup/CleanupActionsListModelTest.java b/src/test/java/org/jabref/cleanup/CleanupActionsListModelTest.java index 5dd7f262919..885a6d1e109 100644 --- a/src/test/java/org/jabref/cleanup/CleanupActionsListModelTest.java +++ b/src/test/java/org/jabref/cleanup/CleanupActionsListModelTest.java @@ -14,10 +14,10 @@ import org.jabref.model.cleanup.FieldFormatterCleanup; import org.jabref.model.cleanup.FieldFormatterCleanups; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyZeroInteractions; diff --git a/src/test/java/org/jabref/cli/AuxCommandLineTest.java b/src/test/java/org/jabref/cli/AuxCommandLineTest.java index f145903b2e9..81e81952062 100644 --- a/src/test/java/org/jabref/cli/AuxCommandLineTest.java +++ b/src/test/java/org/jabref/cli/AuxCommandLineTest.java @@ -14,18 +14,19 @@ import org.jabref.model.database.BibDatabase; import org.jabref.model.util.DummyFileUpdateMonitor; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.mockito.Answers; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.mockito.Mockito.mock; public class AuxCommandLineTest { private ImportFormatPreferences importFormatPreferences; - @Before + @BeforeEach public void setUp() throws Exception { importFormatPreferences = mock(ImportFormatPreferences.class, Answers.RETURNS_DEEP_STUBS); } @@ -40,8 +41,8 @@ public void test() throws URISyntaxException, IOException { AuxCommandLine auxCommandLine = new AuxCommandLine(auxFile.getAbsolutePath(), result.getDatabase()); BibDatabase newDB = auxCommandLine.perform(); - Assert.assertNotNull(newDB); - Assert.assertEquals(2, newDB.getEntries().size()); + assertNotNull(newDB); + assertEquals(2, newDB.getEntries().size()); } } diff --git a/src/test/java/org/jabref/cli/JabRefCLITest.java b/src/test/java/org/jabref/cli/JabRefCLITest.java index 0d59160e0d2..bab13945e9e 100644 --- a/src/test/java/org/jabref/cli/JabRefCLITest.java +++ b/src/test/java/org/jabref/cli/JabRefCLITest.java @@ -2,8 +2,10 @@ import java.util.Collections; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; public class JabRefCLITest { @@ -11,29 +13,29 @@ public class JabRefCLITest { public void testCLIParsingLongOptions() { JabRefCLI cli = new JabRefCLI(new String[] {"--nogui", "--import=some/file", "--output=some/export/file"}); - Assert.assertEquals(Collections.emptyList(), cli.getLeftOver()); - Assert.assertEquals("some/file", cli.getFileImport()); - Assert.assertTrue(cli.isDisableGui()); - Assert.assertEquals("some/export/file", cli.getFileExport()); + assertEquals(Collections.emptyList(), cli.getLeftOver()); + assertEquals("some/file", cli.getFileImport()); + assertTrue(cli.isDisableGui()); + assertEquals("some/export/file", cli.getFileExport()); } @Test public void testCLIParsingShortOptions() { JabRefCLI cli = new JabRefCLI(new String[] {"-n", "-i=some/file", "-o=some/export/file"}); - Assert.assertEquals(Collections.emptyList(), cli.getLeftOver()); - Assert.assertEquals("some/file", cli.getFileImport()); - Assert.assertTrue(cli.isDisableGui()); - Assert.assertEquals("some/export/file", cli.getFileExport()); + assertEquals(Collections.emptyList(), cli.getLeftOver()); + assertEquals("some/file", cli.getFileImport()); + assertTrue(cli.isDisableGui()); + assertEquals("some/export/file", cli.getFileExport()); } @Test public void testPreferencesExport() { JabRefCLI cli = new JabRefCLI(new String[] {"-n", "-x=some/file"}); - Assert.assertEquals(Collections.emptyList(), cli.getLeftOver()); - Assert.assertEquals("some/file", cli.getPreferencesExport()); - Assert.assertTrue(cli.isDisableGui()); + assertEquals(Collections.emptyList(), cli.getLeftOver()); + assertEquals("some/file", cli.getPreferencesExport()); + assertTrue(cli.isDisableGui()); } } diff --git a/src/test/java/org/jabref/gui/autocompleter/BibEntrySuggestionProviderTest.java b/src/test/java/org/jabref/gui/autocompleter/BibEntrySuggestionProviderTest.java index b66163a940d..6d7c30023f4 100644 --- a/src/test/java/org/jabref/gui/autocompleter/BibEntrySuggestionProviderTest.java +++ b/src/test/java/org/jabref/gui/autocompleter/BibEntrySuggestionProviderTest.java @@ -6,16 +6,18 @@ import org.jabref.model.entry.BibEntry; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import static org.jabref.gui.autocompleter.AutoCompleterUtil.getRequest; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; public class BibEntrySuggestionProviderTest { + private BibEntrySuggestionProvider autoCompleter; - @Before + @BeforeEach public void setUp() throws Exception { autoCompleter = new BibEntrySuggestionProvider(); } @@ -23,7 +25,7 @@ public void setUp() throws Exception { @Test public void completeWithoutAddingAnythingReturnsNothing() { Collection result = autoCompleter.call(getRequest(("test"))); - Assert.assertEquals(Collections.emptyList(), result); + assertEquals(Collections.emptyList(), result); } @Test @@ -31,7 +33,7 @@ public void completeAfterAddingNullReturnsNothing() { autoCompleter.indexEntry(null); Collection result = autoCompleter.call(getRequest(("test"))); - Assert.assertEquals(Collections.emptyList(), result); + assertEquals(Collections.emptyList(), result); } @Test @@ -40,7 +42,7 @@ public void completeAfterAddingEmptyEntryReturnsNothing() { autoCompleter.indexEntry(entry); Collection result = autoCompleter.call(getRequest(("test"))); - Assert.assertEquals(Collections.emptyList(), result); + assertEquals(Collections.emptyList(), result); } @Test @@ -50,7 +52,7 @@ public void completeKeyReturnsKey() { autoCompleter.indexEntry(entry); Collection result = autoCompleter.call(getRequest(("testKey"))); - Assert.assertEquals(Collections.singletonList(entry), result); + assertEquals(Collections.singletonList(entry), result); } @Test @@ -60,7 +62,7 @@ public void completeBeginnigOfKeyReturnsKey() { autoCompleter.indexEntry(entry); Collection result = autoCompleter.call(getRequest(("test"))); - Assert.assertEquals(Collections.singletonList(entry), result); + assertEquals(Collections.singletonList(entry), result); } @Test @@ -70,16 +72,15 @@ public void completeLowercaseKeyReturnsKey() { autoCompleter.indexEntry(entry); Collection result = autoCompleter.call(getRequest(("testkey"))); - Assert.assertEquals(Collections.singletonList(entry), result); + assertEquals(Collections.singletonList(entry), result); } - @Test(expected = NullPointerException.class) public void completeNullThrowsException() { BibEntry entry = new BibEntry(); entry.setCiteKey("testKey"); autoCompleter.indexEntry(entry); - autoCompleter.call(getRequest((null))); + assertThrows(NullPointerException.class, () -> autoCompleter.call(getRequest((null)))); } @Test @@ -89,7 +90,7 @@ public void completeEmptyStringReturnsNothing() { autoCompleter.indexEntry(entry); Collection result = autoCompleter.call(getRequest((""))); - Assert.assertEquals(Collections.emptyList(), result); + assertEquals(Collections.emptyList(), result); } @Test @@ -102,7 +103,7 @@ public void completeReturnsMultipleResults() { autoCompleter.indexEntry(entryTwo); Collection result = autoCompleter.call(getRequest(("testKey"))); - Assert.assertEquals(Arrays.asList(entryTwo, entryOne), result); + assertEquals(Arrays.asList(entryTwo, entryOne), result); } @Test @@ -112,6 +113,6 @@ public void completeShortKeyReturnsKey() { autoCompleter.indexEntry(entry); Collection result = autoCompleter.call(getRequest(("k"))); - Assert.assertEquals(Collections.singletonList(entry), result); + assertEquals(Collections.singletonList(entry), result); } } diff --git a/src/test/java/org/jabref/gui/autocompleter/DefaultAutoCompleterTest.java b/src/test/java/org/jabref/gui/autocompleter/DefaultAutoCompleterTest.java index 5983d43da57..8a55ecadd10 100644 --- a/src/test/java/org/jabref/gui/autocompleter/DefaultAutoCompleterTest.java +++ b/src/test/java/org/jabref/gui/autocompleter/DefaultAutoCompleterTest.java @@ -6,23 +6,22 @@ import org.jabref.model.entry.BibEntry; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import static org.jabref.gui.autocompleter.AutoCompleterUtil.getRequest; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; public class DefaultAutoCompleterTest { private WordSuggestionProvider autoCompleter; - @SuppressWarnings("unused") - @Test(expected = NullPointerException.class) public void initAutoCompleterWithNullFieldThrowsException() { - new WordSuggestionProvider(null); + assertThrows(NullPointerException.class, () -> new WordSuggestionProvider(null)); } - @Before + @BeforeEach public void setUp() throws Exception { autoCompleter = new WordSuggestionProvider("field"); } @@ -30,7 +29,7 @@ public void setUp() throws Exception { @Test public void completeWithoutAddingAnythingReturnsNothing() { Collection result = autoCompleter.call(getRequest(("test"))); - Assert.assertEquals(Collections.emptyList(), result); + assertEquals(Collections.emptyList(), result); } @Test @@ -38,7 +37,7 @@ public void completeAfterAddingNullReturnsNothing() { autoCompleter.indexEntry(null); Collection result = autoCompleter.call(getRequest(("test"))); - Assert.assertEquals(Collections.emptyList(), result); + assertEquals(Collections.emptyList(), result); } @Test @@ -47,7 +46,7 @@ public void completeAfterAddingEmptyEntryReturnsNothing() { autoCompleter.indexEntry(entry); Collection result = autoCompleter.call(getRequest(("test"))); - Assert.assertEquals(Collections.emptyList(), result); + assertEquals(Collections.emptyList(), result); } @Test @@ -57,7 +56,7 @@ public void completeAfterAddingEntryWithoutFieldReturnsNothing() { autoCompleter.indexEntry(entry); Collection result = autoCompleter.call(getRequest(("test"))); - Assert.assertEquals(Collections.emptyList(), result); + assertEquals(Collections.emptyList(), result); } @Test @@ -67,7 +66,7 @@ public void completeValueReturnsValue() { autoCompleter.indexEntry(entry); Collection result = autoCompleter.call(getRequest(("testValue"))); - Assert.assertEquals(Arrays.asList("testValue"), result); + assertEquals(Arrays.asList("testValue"), result); } @Test @@ -77,7 +76,7 @@ public void completeBeginnigOfValueReturnsValue() { autoCompleter.indexEntry(entry); Collection result = autoCompleter.call(getRequest(("test"))); - Assert.assertEquals(Arrays.asList("testValue"), result); + assertEquals(Arrays.asList("testValue"), result); } @Test @@ -87,16 +86,15 @@ public void completeLowercaseValueReturnsValue() { autoCompleter.indexEntry(entry); Collection result = autoCompleter.call(getRequest(("testvalue"))); - Assert.assertEquals(Arrays.asList("testValue"), result); + assertEquals(Arrays.asList("testValue"), result); } - @Test(expected = NullPointerException.class) public void completeNullThrowsException() { BibEntry entry = new BibEntry(); entry.setField("field", "testKey"); autoCompleter.indexEntry(entry); - autoCompleter.call(getRequest((null))); + assertThrows(NullPointerException.class, () -> autoCompleter.call(getRequest((null)))); } @Test @@ -106,7 +104,7 @@ public void completeEmptyStringReturnsNothing() { autoCompleter.indexEntry(entry); Collection result = autoCompleter.call(getRequest((""))); - Assert.assertEquals(Collections.emptyList(), result); + assertEquals(Collections.emptyList(), result); } @Test @@ -119,7 +117,7 @@ public void completeReturnsMultipleResults() { autoCompleter.indexEntry(entryTwo); Collection result = autoCompleter.call(getRequest(("testValue"))); - Assert.assertEquals(Arrays.asList("testValueOne", "testValueTwo"), result); + assertEquals(Arrays.asList("testValueOne", "testValueTwo"), result); } @Test @@ -129,7 +127,7 @@ public void completeShortStringReturnsValue() { autoCompleter.indexEntry(entry); Collection result = autoCompleter.call(getRequest(("va"))); - Assert.assertEquals(Collections.singletonList("val"), result); + assertEquals(Collections.singletonList("val"), result); } @Test @@ -139,7 +137,7 @@ public void completeBeginnigOfSecondWordReturnsWord() { autoCompleter.indexEntry(entry); Collection result = autoCompleter.call(getRequest(("val"))); - Assert.assertEquals(Collections.singletonList("value"), result); + assertEquals(Collections.singletonList("value"), result); } @Test @@ -149,6 +147,6 @@ public void completePartOfWordReturnsValue() { autoCompleter.indexEntry(entry); Collection result = autoCompleter.call(getRequest(("lue"))); - Assert.assertEquals(Collections.singletonList("value"), result); + assertEquals(Collections.singletonList("value"), result); } } diff --git a/src/test/java/org/jabref/gui/autocompleter/FieldValueSuggestionProviderTest.java b/src/test/java/org/jabref/gui/autocompleter/FieldValueSuggestionProviderTest.java index 1ecf2600084..ffe219b6200 100644 --- a/src/test/java/org/jabref/gui/autocompleter/FieldValueSuggestionProviderTest.java +++ b/src/test/java/org/jabref/gui/autocompleter/FieldValueSuggestionProviderTest.java @@ -6,30 +6,30 @@ import org.jabref.model.entry.BibEntry; -import org.junit.Assert; -import org.junit.Before; import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; import static org.jabref.gui.autocompleter.AutoCompleterUtil.getRequest; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; public class FieldValueSuggestionProviderTest { + private FieldValueSuggestionProvider autoCompleter; - @Before + @BeforeEach public void setUp() throws Exception { autoCompleter = new FieldValueSuggestionProvider("field"); } - @SuppressWarnings("unused") - @Test(expected = NullPointerException.class) public void initAutoCompleterWithNullFieldThrowsException() { - new FieldValueSuggestionProvider(null); + assertThrows(NullPointerException.class, () -> new FieldValueSuggestionProvider(null)); } @Test public void completeWithoutAddingAnythingReturnsNothing() { Collection result = autoCompleter.call(getRequest(("test"))); - Assert.assertEquals(Collections.emptyList(), result); + assertEquals(Collections.emptyList(), result); } @Test @@ -37,7 +37,7 @@ public void completeAfterAddingNullReturnsNothing() { autoCompleter.indexEntry(null); Collection result = autoCompleter.call(getRequest(("test"))); - Assert.assertEquals(Collections.emptyList(), result); + assertEquals(Collections.emptyList(), result); } @Test @@ -46,7 +46,7 @@ public void completeAfterAddingEmptyEntryReturnsNothing() { autoCompleter.indexEntry(entry); Collection result = autoCompleter.call(getRequest(("test"))); - Assert.assertEquals(Collections.emptyList(), result); + assertEquals(Collections.emptyList(), result); } @Test @@ -56,7 +56,7 @@ public void completeAfterAddingEntryWithoutFieldReturnsNothing() { autoCompleter.indexEntry(entry); Collection result = autoCompleter.call(getRequest(("test"))); - Assert.assertEquals(Collections.emptyList(), result); + assertEquals(Collections.emptyList(), result); } @Test @@ -66,7 +66,7 @@ public void completeValueReturnsValue() { autoCompleter.indexEntry(entry); Collection result = autoCompleter.call(getRequest(("testValue"))); - Assert.assertEquals(Arrays.asList("testValue"), result); + assertEquals(Arrays.asList("testValue"), result); } @Test @@ -76,7 +76,7 @@ public void completeBeginnigOfValueReturnsValue() { autoCompleter.indexEntry(entry); Collection result = autoCompleter.call(getRequest(("test"))); - Assert.assertEquals(Arrays.asList("testValue"), result); + assertEquals(Arrays.asList("testValue"), result); } @Test @@ -86,7 +86,7 @@ public void completeLowercaseValueReturnsValue() { autoCompleter.indexEntry(entry); Collection result = autoCompleter.call(getRequest(("testvalue"))); - Assert.assertEquals(Arrays.asList("testValue"), result); + assertEquals(Arrays.asList("testValue"), result); } @Test(expected = NullPointerException.class) @@ -105,7 +105,7 @@ public void completeEmptyStringReturnsNothing() { autoCompleter.indexEntry(entry); Collection result = autoCompleter.call(getRequest((""))); - Assert.assertEquals(Collections.emptyList(), result); + assertEquals(Collections.emptyList(), result); } @Test @@ -118,7 +118,7 @@ public void completeReturnsMultipleResults() { autoCompleter.indexEntry(entryTwo); Collection result = autoCompleter.call(getRequest(("testValue"))); - Assert.assertEquals(Arrays.asList("testValueOne", "testValueTwo"), result); + assertEquals(Arrays.asList("testValueOne", "testValueTwo"), result); } @Test @@ -128,7 +128,7 @@ public void completeShortStringReturnsFieldValue() { autoCompleter.indexEntry(entry); Collection result = autoCompleter.call(getRequest(("va"))); - Assert.assertEquals(Collections.singletonList("val"), result); + assertEquals(Collections.singletonList("val"), result); } @Test @@ -138,7 +138,7 @@ public void completeBeginnigOfSecondWordReturnsWholeFieldValue() { autoCompleter.indexEntry(entry); Collection result = autoCompleter.call(getRequest(("val"))); - Assert.assertEquals(Collections.singletonList("test value"), result); + assertEquals(Collections.singletonList("test value"), result); } @Test @@ -148,7 +148,7 @@ public void completePartOfWordReturnsWholeFieldValue() { autoCompleter.indexEntry(entry); Collection result = autoCompleter.call(getRequest(("lue"))); - Assert.assertEquals(Collections.singletonList("test value"), result); + assertEquals(Collections.singletonList("test value"), result); } @Test @@ -158,6 +158,6 @@ public void completeReturnsWholeFieldValue() { autoCompleter.indexEntry(entry); Collection result = autoCompleter.call(getRequest(("te"))); - Assert.assertEquals(Collections.singletonList("test value"), result); + assertEquals(Collections.singletonList("test value"), result); } } diff --git a/src/test/java/org/jabref/gui/autocompleter/PersonNameSuggestionProviderTest.java b/src/test/java/org/jabref/gui/autocompleter/PersonNameSuggestionProviderTest.java index 9b4365b08dd..9974cf50ef5 100644 --- a/src/test/java/org/jabref/gui/autocompleter/PersonNameSuggestionProviderTest.java +++ b/src/test/java/org/jabref/gui/autocompleter/PersonNameSuggestionProviderTest.java @@ -7,11 +7,12 @@ import org.jabref.model.entry.Author; import org.jabref.model.entry.BibEntry; -import org.junit.Assert; import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.Test; import static org.jabref.gui.autocompleter.AutoCompleterUtil.getRequest; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; public class PersonNameSuggestionProviderTest { @@ -19,9 +20,8 @@ public class PersonNameSuggestionProviderTest { private PersonNameSuggestionProvider autoCompleter; private BibEntry entry; - @Test(expected = NullPointerException.class) public void initAutoCompleterWithNullFieldThrowsException() { - new PersonNameSuggestionProvider((String) null); + assertThrows(NullPointerException.class, () -> new PersonNameSuggestionProvider((String) null)); } @Before @@ -35,7 +35,7 @@ public void setUp() throws Exception { @Test public void completeWithoutAddingAnythingReturnsNothing() { Collection result = autoCompleter.call(getRequest(("test"))); - Assert.assertEquals(Collections.emptyList(), result); + assertEquals(Collections.emptyList(), result); } @Test @@ -43,7 +43,7 @@ public void completeAfterAddingNullReturnsNothing() { autoCompleter.indexEntry(null); Collection result = autoCompleter.call(getRequest(("test"))); - Assert.assertEquals(Collections.emptyList(), result); + assertEquals(Collections.emptyList(), result); } @Test @@ -52,7 +52,7 @@ public void completeAfterAddingEmptyEntryReturnsNothing() { autoCompleter.indexEntry(entry); Collection result = autoCompleter.call(getRequest(("test"))); - Assert.assertEquals(Collections.emptyList(), result); + assertEquals(Collections.emptyList(), result); } @Test @@ -62,7 +62,7 @@ public void completeAfterAddingEntryWithoutFieldReturnsNothing() { autoCompleter.indexEntry(entry); Collection result = autoCompleter.call(getRequest(("test"))); - Assert.assertEquals(Collections.emptyList(), result); + assertEquals(Collections.emptyList(), result); } @Test @@ -70,7 +70,7 @@ public void completeNameReturnsName() { autoCompleter.indexEntry(entry); Collection result = autoCompleter.call(getRequest(("Kostakos"))); - Assert.assertEquals(Collections.singletonList(vassilisKostakos), result); + assertEquals(Collections.singletonList(vassilisKostakos), result); } @Test @@ -78,7 +78,7 @@ public void completeBeginningOfNameReturnsName() { autoCompleter.indexEntry(entry); Collection result = autoCompleter.call(getRequest(("Kosta"))); - Assert.assertEquals(Collections.singletonList(vassilisKostakos), result); + assertEquals(Collections.singletonList(vassilisKostakos), result); } @Test @@ -86,12 +86,11 @@ public void completeLowercaseBeginningOfNameReturnsName() { autoCompleter.indexEntry(entry); Collection result = autoCompleter.call(getRequest(("kosta"))); - Assert.assertEquals(Collections.singletonList(vassilisKostakos), result); + assertEquals(Collections.singletonList(vassilisKostakos), result); } - @Test(expected = NullPointerException.class) public void completeNullThrowsException() { - autoCompleter.call(getRequest((null))); + assertThrows(NullPointerException.class, () -> autoCompleter.call(getRequest((null)))); } @Test @@ -99,7 +98,7 @@ public void completeEmptyStringReturnsNothing() { autoCompleter.indexEntry(entry); Collection result = autoCompleter.call(getRequest((""))); - Assert.assertEquals(Collections.emptyList(), result); + assertEquals(Collections.emptyList(), result); } @Test @@ -111,7 +110,7 @@ public void completeReturnsMultipleResults() { Author authorTwo = new Author("", "", "", "Kosta", ""); Collection result = autoCompleter.call(getRequest(("Ko"))); - Assert.assertEquals(Arrays.asList(authorTwo, vassilisKostakos), result); + assertEquals(Arrays.asList(authorTwo, vassilisKostakos), result); } @Test @@ -119,7 +118,7 @@ public void completePartOfNameReturnsName() { autoCompleter.indexEntry(entry); Collection result = autoCompleter.call(getRequest(("osta"))); - Assert.assertEquals(Collections.singletonList(vassilisKostakos), result); + assertEquals(Collections.singletonList(vassilisKostakos), result); } @Test @@ -127,7 +126,7 @@ public void completeBeginningOfFirstNameReturnsName() { autoCompleter.indexEntry(entry); Collection result = autoCompleter.call(getRequest(("Vas"))); - Assert.assertEquals(Collections.singletonList(vassilisKostakos), result); + assertEquals(Collections.singletonList(vassilisKostakos), result); } @Test @@ -138,7 +137,7 @@ public void completeBeginningOfFirstNameReturnsNameWithJr() { Author author = new Author("Joseph M.", "J. M.", "", "Reagle", "Jr."); Collection result = autoCompleter.call(getRequest(("Jos"))); - Assert.assertEquals(Collections.singletonList(author), result); + assertEquals(Collections.singletonList(author), result); } @Test @@ -149,7 +148,7 @@ public void completeBeginningOfFirstNameReturnsNameWithVon() { Author author = new Author("Eric", "E.", "von", "Hippel", ""); Collection result = autoCompleter.call(getRequest(("Eric"))); - Assert.assertEquals(Collections.singletonList(author), result); + assertEquals(Collections.singletonList(author), result); } @Test @@ -160,7 +159,7 @@ public void completeBeginningOfLastNameReturnsNameWithUmlauts() { Author author = new Author("Honig", "H.", "", "Bär", ""); Collection result = autoCompleter.call(getRequest(("Bä"))); - Assert.assertEquals(Collections.singletonList(author), result); + assertEquals(Collections.singletonList(author), result); } @Test @@ -171,7 +170,7 @@ public void completeVonReturnsName() { Author author = new Author("Eric", "E.", "von", "Hippel", ""); Collection result = autoCompleter.call(getRequest(("von"))); - Assert.assertEquals(Collections.singletonList(author), result); + assertEquals(Collections.singletonList(author), result); } @Test @@ -181,6 +180,6 @@ public void completeBeginningOfFullNameReturnsName() { autoCompleter.indexEntry(entry); Collection result = autoCompleter.call(getRequest(("Kostakos, Va"))); - Assert.assertEquals(Collections.singletonList(vassilisKostakos), result); + assertEquals(Collections.singletonList(vassilisKostakos), result); } } diff --git a/src/test/java/org/jabref/gui/externalfiletype/ExternalFileTypeTest.java b/src/test/java/org/jabref/gui/externalfiletype/ExternalFileTypeTest.java index b3c9ea14cac..5ac0251c147 100644 --- a/src/test/java/org/jabref/gui/externalfiletype/ExternalFileTypeTest.java +++ b/src/test/java/org/jabref/gui/externalfiletype/ExternalFileTypeTest.java @@ -1,33 +1,26 @@ package org.jabref.gui.externalfiletype; -import org.jabref.testutils.category.GUITest; +import org.junit.jupiter.api.Test; -import org.junit.Test; -import org.junit.experimental.categories.Category; +import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.Assert.assertNotNull; - -@Category(GUITest.class) public class ExternalFileTypeTest { @Test public void getOpenWithApplicationMustNotReturnNull() throws Exception { ExternalFileType type = new ExternalFileType(null, null, null, null, null, null); - assertNotNull(type.getOpenWithApplication()); } @Test public void getExtensionMustNotReturnNull() throws Exception { ExternalFileType type = new ExternalFileType(null, null, null, null, null, null); - assertNotNull(type.getExtension()); } @Test public void getMimeTypeMustNotReturnNull() throws Exception { ExternalFileType type = new ExternalFileType(null, null, null, null, null, null); - assertNotNull(type.getMimeType()); } diff --git a/src/test/java/org/jabref/gui/fieldeditors/HtmlTransferableTest.java b/src/test/java/org/jabref/gui/fieldeditors/HtmlTransferableTest.java index acd344ef7b8..0577cc73e7f 100644 --- a/src/test/java/org/jabref/gui/fieldeditors/HtmlTransferableTest.java +++ b/src/test/java/org/jabref/gui/fieldeditors/HtmlTransferableTest.java @@ -4,9 +4,9 @@ import org.jabref.logic.util.OS; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class HtmlTransferableTest { diff --git a/src/test/java/org/jabref/gui/fieldeditors/IdentifierEditorViewModelTest.java b/src/test/java/org/jabref/gui/fieldeditors/IdentifierEditorViewModelTest.java index d681344d9b0..80fde0cb66c 100644 --- a/src/test/java/org/jabref/gui/fieldeditors/IdentifierEditorViewModelTest.java +++ b/src/test/java/org/jabref/gui/fieldeditors/IdentifierEditorViewModelTest.java @@ -5,8 +5,8 @@ import org.jabref.gui.util.CurrentThreadTaskExecutor; import org.jabref.logic.integrity.FieldCheckers; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.mock; @@ -15,7 +15,7 @@ public class IdentifierEditorViewModelTest { private IdentifierEditorViewModel viewModel; - @Before + @BeforeEach public void setUp() throws Exception { viewModel = new IdentifierEditorViewModel("DOI", new WordSuggestionProvider("DOI"), new CurrentThreadTaskExecutor(), mock(DialogService.class), mock(FieldCheckers.class)); } diff --git a/src/test/java/org/jabref/gui/groups/GroupNodeViewModelTest.java b/src/test/java/org/jabref/gui/groups/GroupNodeViewModelTest.java index d9e53c6e5ab..e9ad5eade51 100644 --- a/src/test/java/org/jabref/gui/groups/GroupNodeViewModelTest.java +++ b/src/test/java/org/jabref/gui/groups/GroupNodeViewModelTest.java @@ -18,11 +18,11 @@ import org.jabref.model.groups.GroupTreeNode; import org.jabref.model.groups.WordKeywordGroup; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -33,7 +33,7 @@ public class GroupNodeViewModelTest { private GroupNodeViewModel viewModel; private TaskExecutor taskExecutor; - @Before + @BeforeEach public void setUp() throws Exception { stateManager = mock(StateManager.class); when(stateManager.getSelectedEntries()).thenReturn(FXCollections.emptyObservableList()); diff --git a/src/test/java/org/jabref/gui/groups/GroupTreeViewModelTest.java b/src/test/java/org/jabref/gui/groups/GroupTreeViewModelTest.java index 6663c6acd64..79738eeea28 100644 --- a/src/test/java/org/jabref/gui/groups/GroupTreeViewModelTest.java +++ b/src/test/java/org/jabref/gui/groups/GroupTreeViewModelTest.java @@ -10,14 +10,14 @@ import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.FieldName; import org.jabref.model.groups.AllEntriesGroup; - import org.jabref.model.groups.ExplicitGroup; import org.jabref.model.groups.GroupHierarchyType; import org.jabref.model.groups.WordKeywordGroup; -import org.junit.Before; -import org.junit.Test; -import static org.junit.Assert.assertEquals; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.mock; public class GroupTreeViewModelTest { @@ -26,7 +26,7 @@ public class GroupTreeViewModelTest { BibDatabaseContext databaseContext; private TaskExecutor taskExecutor; - @Before + @BeforeEach public void setUp() throws Exception { databaseContext = new BibDatabaseContext(); stateManager = new StateManager(); diff --git a/src/test/java/org/jabref/gui/importer/EntryFromFileCreatorManagerTest.java b/src/test/java/org/jabref/gui/importer/EntryFromFileCreatorManagerTest.java index 7523d3f79b6..5d3c9aa9411 100644 --- a/src/test/java/org/jabref/gui/importer/EntryFromFileCreatorManagerTest.java +++ b/src/test/java/org/jabref/gui/importer/EntryFromFileCreatorManagerTest.java @@ -17,32 +17,28 @@ import org.jabref.model.util.DummyFileUpdateMonitor; import org.jabref.testutils.category.GUITest; -import org.junit.Assert; -import org.junit.Before; import org.junit.Ignore; -import org.junit.Test; -import org.junit.experimental.categories.Category; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.mock; -@Category(GUITest.class) +@GUITest public class EntryFromFileCreatorManagerTest { - // Needed to initialize ExternalFileTypes - @Before - public void setUp() { - - } - @Test public void testGetCreator() { EntryFromFileCreatorManager manager = new EntryFromFileCreatorManager(); EntryFromFileCreator creator = manager.getEntryCreator(ImportDataTest.NOT_EXISTING_PDF); - Assert.assertNull(creator); + assertNull(creator); creator = manager.getEntryCreator(ImportDataTest.FILE_IN_DATABASE); - Assert.assertNotNull(creator); - Assert.assertTrue(creator.accept(ImportDataTest.FILE_IN_DATABASE)); + assertNotNull(creator); + assertTrue(creator.accept(ImportDataTest.FILE_IN_DATABASE)); } @Test @@ -64,7 +60,7 @@ public void testAddEntrysFromFiles() throws IOException { /** * One file doesn't exist, so adding it as an entry should lead to an error message. */ - Assert.assertEquals(1, errors.size()); + assertEquals(1, errors.size()); boolean file1Found = false; boolean file2Found = false; @@ -78,8 +74,8 @@ public void testAddEntrysFromFiles() throws IOException { } } - Assert.assertTrue(file1Found); - Assert.assertFalse(file2Found); + assertTrue(file1Found); + assertFalse(file2Found); } } diff --git a/src/test/java/org/jabref/gui/importer/EntryFromPDFCreatorTest.java b/src/test/java/org/jabref/gui/importer/EntryFromPDFCreatorTest.java index 10b44f11b9d..b2f830ae0d1 100644 --- a/src/test/java/org/jabref/gui/importer/EntryFromPDFCreatorTest.java +++ b/src/test/java/org/jabref/gui/importer/EntryFromPDFCreatorTest.java @@ -9,21 +9,21 @@ import org.jabref.model.entry.BibEntry; import org.jabref.testutils.category.GUITest; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; -import org.junit.experimental.categories.Category; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.mock; -@Category(GUITest.class) +@GUITest public class EntryFromPDFCreatorTest { private EntryFromPDFCreator entryCreator; - - @Before + @BeforeEach public void setUp() { // Needed to initialize ExternalFileTypes entryCreator = new EntryFromPDFCreator(); @@ -33,24 +33,24 @@ public void setUp() { @Test public void testPDFFileFilter() { - Assert.assertTrue(entryCreator.accept(new File("aPDF.pdf"))); - Assert.assertTrue(entryCreator.accept(new File("aPDF.PDF"))); - Assert.assertFalse(entryCreator.accept(new File("foo.jpg"))); + assertTrue(entryCreator.accept(new File("aPDF.pdf"))); + assertTrue(entryCreator.accept(new File("aPDF.PDF"))); + assertFalse(entryCreator.accept(new File("foo.jpg"))); } @Test public void testCreationOfEntryNoPDF() { Optional entry = entryCreator.createEntry(ImportDataTest.NOT_EXISTING_PDF, false); - Assert.assertFalse(entry.isPresent()); + assertFalse(entry.isPresent()); } @Test - @Ignore //Can't mock basepanel and maintable + @Disabled //Can't mock basepanel and maintable public void testCreationOfEntryNotInDatabase() { Optional entry = entryCreator.createEntry(ImportDataTest.FILE_NOT_IN_DATABASE, false); - Assert.assertTrue(entry.isPresent()); - Assert.assertTrue(entry.get().getField("file").get().endsWith(":PDF")); - Assert.assertEquals(Optional.of(ImportDataTest.FILE_NOT_IN_DATABASE.getName()), + assertTrue(entry.isPresent()); + assertTrue(entry.get().getField("file").get().endsWith(":PDF")); + assertEquals(Optional.of(ImportDataTest.FILE_NOT_IN_DATABASE.getName()), entry.get().getField("title")); } diff --git a/src/test/java/org/jabref/gui/importer/fetcher/OAI2HandlerFetcherTest.java b/src/test/java/org/jabref/gui/importer/fetcher/OAI2HandlerFetcherTest.java index f6e3d27269f..46dd1e87880 100644 --- a/src/test/java/org/jabref/gui/importer/fetcher/OAI2HandlerFetcherTest.java +++ b/src/test/java/org/jabref/gui/importer/fetcher/OAI2HandlerFetcherTest.java @@ -9,15 +9,17 @@ import org.jabref.logic.importer.util.OAI2Handler; import org.jabref.model.entry.BibEntry; -import org.jabref.testutils.category.GUITest; +import org.jabref.testutils.category.FetcherTest; -import org.junit.Assert; -import org.junit.Before; import org.junit.Ignore; -import org.junit.Test; -import org.junit.experimental.categories.Category; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.xml.sax.SAXException; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + /** * Test for OAI2-Handler and Fetcher. * @@ -26,7 +28,7 @@ * @author Christopher Oezbek */ -@Category(GUITest.class) +@FetcherTest public class OAI2HandlerFetcherTest { protected OAI2Handler handler; @@ -38,7 +40,7 @@ public class OAI2HandlerFetcherTest { protected SAXParser saxParser; - @Before + @BeforeEach public void setUp() throws ParserConfigurationException, SAXException { parserFactory = SAXParserFactory.newInstance(); saxParser = parserFactory.newSAXParser(); @@ -48,33 +50,33 @@ public void setUp() throws ParserConfigurationException, SAXException { @Test public void testCorrectLineBreaks() { - Assert.assertEquals("Test this", OAI2Handler.correctLineBreaks("Test\nthis")); - Assert.assertEquals("Test this", OAI2Handler.correctLineBreaks("Test \n this")); - Assert.assertEquals("Test\nthis", OAI2Handler.correctLineBreaks("Test\n\nthis")); - Assert.assertEquals("Test\nthis", OAI2Handler.correctLineBreaks("Test\n \nthis")); - Assert.assertEquals("Test\nthis", OAI2Handler.correctLineBreaks(" Test \n \n this ")); + assertEquals("Test this", OAI2Handler.correctLineBreaks("Test\nthis")); + assertEquals("Test this", OAI2Handler.correctLineBreaks("Test \n this")); + assertEquals("Test\nthis", OAI2Handler.correctLineBreaks("Test\n\nthis")); + assertEquals("Test\nthis", OAI2Handler.correctLineBreaks("Test\n \nthis")); + assertEquals("Test\nthis", OAI2Handler.correctLineBreaks(" Test \n \n this ")); } @Test public void testParse() throws Throwable { try { saxParser.parse(this.getClass().getResourceAsStream("oai2.xml"), handler); - Assert.assertEquals(Optional.of("hep-ph/0408155"), be.getField("eprint")); - Assert.assertEquals(Optional.of("G. F. Giudice and A. Riotto and A. Zaffaroni and J. López-Peña"), + assertEquals(Optional.of("hep-ph/0408155"), be.getField("eprint")); + assertEquals(Optional.of("G. F. Giudice and A. Riotto and A. Zaffaroni and J. López-Peña"), be.getField("author")); - Assert.assertEquals(Optional.of("Nucl.Phys. B"), be.getField("journal")); - Assert.assertEquals(Optional.of("710"), be.getField("volume")); - Assert.assertEquals(Optional.of("2005"), be.getField("year")); - Assert.assertEquals(Optional.of("511-525"), be.getField("pages")); + assertEquals(Optional.of("Nucl.Phys. B"), be.getField("journal")); + assertEquals(Optional.of("710"), be.getField("volume")); + assertEquals(Optional.of("2005"), be.getField("year")); + assertEquals(Optional.of("511-525"), be.getField("pages")); // Citekey is only generated if the user says so in the import // inspection dialog. - Assert.assertEquals(Optional.empty(), be.getCiteKeyOptional()); + assertEquals(Optional.empty(), be.getCiteKeyOptional()); - Assert.assertEquals(Optional.of("Heavy Particles from Inflation"), be.getField("title")); - Assert.assertTrue(be.getField("abstract").isPresent()); - Assert.assertEquals(Optional.of("23 pages"), be.getField("comment")); - Assert.assertEquals(Optional.of("CERN-PH-TH/2004-151"), be.getField("reportno")); + assertEquals(Optional.of("Heavy Particles from Inflation"), be.getField("title")); + assertTrue(be.getField("abstract").isPresent()); + assertEquals(Optional.of("23 pages"), be.getField("comment")); + assertEquals(Optional.of("CERN-PH-TH/2004-151"), be.getField("reportno")); } catch (SAXException e) { throw e.getException(); } @@ -84,7 +86,7 @@ public void testParse() throws Throwable { public void testOai22xml() throws SAXException, IOException { saxParser.parse(this.getClass().getResourceAsStream("oai22.xml"), handler); - Assert.assertEquals(Optional.of("2005"), be.getField("year")); + assertEquals(Optional.of("2005"), be.getField("year")); } @@ -92,18 +94,18 @@ public void testOai22xml() throws SAXException, IOException { public void testOai23xml() throws SAXException, IOException { saxParser.parse(this.getClass().getResourceAsStream("oai23.xml"), handler); - Assert.assertEquals(Optional.of("Javier López Peña and Gabriel Navarro"), be.getField("author")); + assertEquals(Optional.of("Javier López Peña and Gabriel Navarro"), be.getField("author")); } @Test public void testUrlConstructor() { OAI2Fetcher fetcher = new OAI2Fetcher(); - Assert.assertEquals( + assertEquals( "http://export.arxiv.org/oai2?verb=GetRecord&identifier=oai%3AarXiv.org%3Ahep-ph%2F0408155&metadataPrefix=arXiv", fetcher.constructUrl("hep-ph/0408155")); - Assert.assertEquals( + assertEquals( "http://export.arxiv.org/oai2?verb=GetRecord&identifier=oai%3AarXiv.org%3Amath%2F0612188&metadataPrefix=arXiv", fetcher.constructUrl("math/0612188")); @@ -111,13 +113,13 @@ public void testUrlConstructor() { @Test public void testFixKey() { - Assert.assertEquals("", OAI2Fetcher.fixKey("")); - Assert.assertEquals("test", OAI2Fetcher.fixKey("test")); - Assert.assertEquals("math/0601001", OAI2Fetcher.fixKey("math.RA/0601001")); - Assert.assertEquals("math/0601001", OAI2Fetcher.fixKey("math.QA/0601001")); - Assert.assertEquals("hep-ph/0408155", OAI2Fetcher.fixKey("hep-ph/0408155")); - Assert.assertEquals("0709.3040v1", OAI2Fetcher.fixKey("arXiv:0709.3040v1")); - Assert.assertEquals("", OAI2Fetcher.fixKey("arXiv:")); + assertEquals("", OAI2Fetcher.fixKey("")); + assertEquals("test", OAI2Fetcher.fixKey("test")); + assertEquals("math/0601001", OAI2Fetcher.fixKey("math.RA/0601001")); + assertEquals("math/0601001", OAI2Fetcher.fixKey("math.QA/0601001")); + assertEquals("hep-ph/0408155", OAI2Fetcher.fixKey("hep-ph/0408155")); + assertEquals("0709.3040v1", OAI2Fetcher.fixKey("arXiv:0709.3040v1")); + assertEquals("", OAI2Fetcher.fixKey("arXiv:")); } @Test @@ -127,13 +129,13 @@ public void testOnline() throws InterruptedException, IOException, SAXException { OAI2Fetcher fetcher = new OAI2Fetcher(); be = fetcher.importOai2Entry("math.RA/0612188"); - Assert.assertNotNull(be); + assertNotNull(be); - Assert.assertEquals(Optional.of("math/0612188"), be.getField("eprint")); - Assert.assertEquals(Optional.of("On the classification and properties of noncommutative duplicates"), + assertEquals(Optional.of("math/0612188"), be.getField("eprint")); + assertEquals(Optional.of("On the classification and properties of noncommutative duplicates"), be.getField("title")); - Assert.assertEquals(Optional.of("Javier López Peña and Gabriel Navarro"), be.getField("author")); - Assert.assertEquals(Optional.of("2007"), be.getField("year")); + assertEquals(Optional.of("Javier López Peña and Gabriel Navarro"), be.getField("author")); + assertEquals(Optional.of("2007"), be.getField("year")); Thread.sleep(20000); } @@ -141,10 +143,10 @@ public void testOnline() throws InterruptedException, IOException, SAXException { OAI2Fetcher fetcher = new OAI2Fetcher(); be = fetcher.importOai2Entry("astro-ph/0702080"); - Assert.assertNotNull(be); + assertNotNull(be); - Assert.assertEquals(Optional.of("astro-ph/0702080"), be.getField("eprint")); - Assert.assertEquals( + assertEquals(Optional.of("astro-ph/0702080"), be.getField("eprint")); + assertEquals( Optional.of( "Magnetized Hypermassive Neutron Star Collapse: a candidate central engine for short-hard GRBs"), be.getField("title")); @@ -155,27 +157,27 @@ public void testOnline() throws InterruptedException, IOException, SAXException { OAI2Fetcher fetcher = new OAI2Fetcher(); be = fetcher.importOai2Entry("math.QA/0601001"); - Assert.assertNotNull(be); + assertNotNull(be); - Assert.assertEquals(Optional.of("math/0601001"), be.getField("eprint")); + assertEquals(Optional.of("math/0601001"), be.getField("eprint")); Thread.sleep(20000); } { OAI2Fetcher fetcher = new OAI2Fetcher(); be = fetcher.importOai2Entry("hep-ph/0408155"); - Assert.assertNotNull(be); + assertNotNull(be); - Assert.assertEquals(Optional.of("hep-ph/0408155"), be.getField("eprint")); + assertEquals(Optional.of("hep-ph/0408155"), be.getField("eprint")); Thread.sleep(20000); } OAI2Fetcher fetcher = new OAI2Fetcher(); be = fetcher.importOai2Entry("0709.3040"); - Assert.assertNotNull(be); + assertNotNull(be); - Assert.assertEquals(Optional.of("2007"), be.getField("year")); - Assert.assertEquals(Optional.of("#sep#"), be.getField("month")); + assertEquals(Optional.of("2007"), be.getField("year")); + assertEquals(Optional.of("#sep#"), be.getField("month")); } } diff --git a/src/test/java/org/jabref/gui/search/ContainsAndRegexBasedSearchRuleDescriberTest.java b/src/test/java/org/jabref/gui/search/ContainsAndRegexBasedSearchRuleDescriberTest.java index 78705c52a47..bc381d7d6d1 100644 --- a/src/test/java/org/jabref/gui/search/ContainsAndRegexBasedSearchRuleDescriberTest.java +++ b/src/test/java/org/jabref/gui/search/ContainsAndRegexBasedSearchRuleDescriberTest.java @@ -9,9 +9,9 @@ import org.jabref.gui.search.rules.describer.ContainsAndRegexBasedSearchRuleDescriber; import org.jabref.gui.util.TooltipTextUtil; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertTrue; public class ContainsAndRegexBasedSearchRuleDescriberTest { diff --git a/src/test/java/org/jabref/gui/search/GrammarBasedSearchRuleDescriberTest.java b/src/test/java/org/jabref/gui/search/GrammarBasedSearchRuleDescriberTest.java index 0831107b681..451be0e80b0 100644 --- a/src/test/java/org/jabref/gui/search/GrammarBasedSearchRuleDescriberTest.java +++ b/src/test/java/org/jabref/gui/search/GrammarBasedSearchRuleDescriberTest.java @@ -10,9 +10,9 @@ import org.jabref.gui.util.TooltipTextUtil; import org.jabref.model.search.rules.GrammarBasedSearchRule; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertTrue; public class GrammarBasedSearchRuleDescriberTest { diff --git a/src/test/java/org/jabref/gui/util/RecursiveTreeItemTest.java b/src/test/java/org/jabref/gui/util/RecursiveTreeItemTest.java index 6f06b4012db..7fb07169950 100644 --- a/src/test/java/org/jabref/gui/util/RecursiveTreeItemTest.java +++ b/src/test/java/org/jabref/gui/util/RecursiveTreeItemTest.java @@ -11,8 +11,8 @@ import org.jabref.model.TreeNode; import org.jabref.model.TreeNodeTestData; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import static org.junit.Assert.assertEquals; @@ -23,7 +23,7 @@ public class RecursiveTreeItemTest { private ObjectProperty> filterPredicate; private TreeNodeTestData.TreeNodeMock node; - @Before + @BeforeEach public void setUp() throws Exception { root = new TreeNodeTestData.TreeNodeMock(); node = TreeNodeTestData.getNodeInSimpleTree(root); diff --git a/src/test/java/org/jabref/gui/util/TooltipTextUtilTest.java b/src/test/java/org/jabref/gui/util/TooltipTextUtilTest.java index 0bd41ea3916..5fc35cca659 100644 --- a/src/test/java/org/jabref/gui/util/TooltipTextUtilTest.java +++ b/src/test/java/org/jabref/gui/util/TooltipTextUtilTest.java @@ -7,8 +7,10 @@ import org.jabref.gui.search.TextFlowEqualityHelper; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; /** * @author jpf @@ -20,32 +22,32 @@ public class TooltipTextUtilTest { public void testCreateText() { String testText = "this is a test text"; Text text = TooltipTextUtil.createText(testText, TooltipTextUtil.TextType.NORMAL); - Assert.assertEquals("Regular", text.getFont().getStyle()); - Assert.assertEquals(testText, text.getText()); + assertEquals("Regular", text.getFont().getStyle()); + assertEquals(testText, text.getText()); } @Test public void testCreateTextBold() { String testText = "this is a test text"; Text text = TooltipTextUtil.createText(testText, TooltipTextUtil.TextType.BOLD); - Assert.assertEquals("tooltip-text-bold", text.getStyleClass().toString()); - Assert.assertEquals(testText, text.getText()); + assertEquals("tooltip-text-bold", text.getStyleClass().toString()); + assertEquals(testText, text.getText()); } @Test public void testCreateTextItalic() { String testText = "this is a test text"; Text text = TooltipTextUtil.createText(testText, TooltipTextUtil.TextType.ITALIC); - Assert.assertEquals("tooltip-text-italic", text.getStyleClass().toString()); - Assert.assertEquals(testText, text.getText()); + assertEquals("tooltip-text-italic", text.getStyleClass().toString()); + assertEquals(testText, text.getText()); } @Test public void testCreateTextMonospaced() { String testText = "this is a test text"; Text text = TooltipTextUtil.createText(testText, TooltipTextUtil.TextType.MONOSPACED); - Assert.assertEquals("tooltip-text-monospaced", text.getStyleClass().toString()); - Assert.assertEquals(testText, text.getText()); + assertEquals("tooltip-text-monospaced", text.getStyleClass().toString()); + assertEquals(testText, text.getText()); } @Test @@ -53,7 +55,7 @@ public void testTextToHTMLStringBold() { String testText = "this is a test text"; Text text = TooltipTextUtil.createText(testText, TooltipTextUtil.TextType.BOLD); String htmlString = TooltipTextUtil.textToHTMLString(text); - Assert.assertEquals("" + testText + "", htmlString); + assertEquals("" + testText + "", htmlString); } @Test @@ -61,7 +63,7 @@ public void testTextToHTMLStringItalic() { String testText = "this is a test text"; Text text = TooltipTextUtil.createText(testText, TooltipTextUtil.TextType.ITALIC); String htmlString = TooltipTextUtil.textToHTMLString(text); - Assert.assertEquals("" + testText + "", htmlString); + assertEquals("" + testText + "", htmlString); } @Test @@ -69,7 +71,7 @@ public void testTextToHTMLStringMonospaced() { String testText = "this is a test text"; Text text = TooltipTextUtil.createText(testText, TooltipTextUtil.TextType.MONOSPACED); String htmlString = TooltipTextUtil.textToHTMLString(text); - Assert.assertEquals("" + testText + "", htmlString); + assertEquals("" + testText + "", htmlString); } @Test @@ -78,7 +80,7 @@ public void testTextToHTMLStringMonospacedBold() { Text text = TooltipTextUtil.createText(testText, TooltipTextUtil.TextType.MONOSPACED); text.getStyleClass().add("tooltip-text-bold"); String htmlString = TooltipTextUtil.textToHTMLString(text); - Assert.assertEquals("" + testText + "", htmlString); + assertEquals("" + testText + "", htmlString); } @Test @@ -86,7 +88,7 @@ public void testTextToHTMLStringWithLinebreaks() { String testText = "this\nis a\ntest text"; Text text = TooltipTextUtil.createText(testText, TooltipTextUtil.TextType.NORMAL); String htmlString = TooltipTextUtil.textToHTMLString(text); - Assert.assertEquals("this
is a
test text", htmlString); + assertEquals("this
is a
test text", htmlString); } @Test @@ -95,10 +97,9 @@ public void testFormatToTextsNoReplacements() { expectedTextList.add(TooltipTextUtil.createText("This search contains entries in which any field contains the regular expression ")); String test = "This search contains entries in which any field contains the regular expression "; List textList = TooltipTextUtil.formatToTexts(test); - Assert.assertTrue(TextFlowEqualityHelper.checkIfTextsEqualsExpectedTexts(expectedTextList, textList)); + assertTrue(TextFlowEqualityHelper.checkIfTextsEqualsExpectedTexts(expectedTextList, textList)); } - @Test public void testFormatToTextsEnd() { List expectedTextList = new ArrayList<>(); @@ -106,7 +107,7 @@ public void testFormatToTextsEnd() { expectedTextList.add(TooltipTextUtil.createText("replacing text", TooltipTextUtil.TextType.BOLD)); String test = "This search contains entries in which any field contains the regular expression %0"; List textList = TooltipTextUtil.formatToTexts(test, new TooltipTextUtil.TextReplacement("%0", "replacing text", TooltipTextUtil.TextType.BOLD)); - Assert.assertTrue(TextFlowEqualityHelper.checkIfTextsEqualsExpectedTexts(expectedTextList, textList)); + assertTrue(TextFlowEqualityHelper.checkIfTextsEqualsExpectedTexts(expectedTextList, textList)); } @Test @@ -116,7 +117,7 @@ public void testFormatToTextsBegin() { expectedTextList.add(TooltipTextUtil.createText(" This search contains entries in which any field contains the regular expression")); String test = "%0 This search contains entries in which any field contains the regular expression"; List textList = TooltipTextUtil.formatToTexts(test, new TooltipTextUtil.TextReplacement("%0", "replacing text", TooltipTextUtil.TextType.BOLD)); - Assert.assertTrue(TextFlowEqualityHelper.checkIfTextsEqualsExpectedTexts(expectedTextList, textList)); + assertTrue(TextFlowEqualityHelper.checkIfTextsEqualsExpectedTexts(expectedTextList, textList)); } @Test @@ -127,6 +128,6 @@ public void testFormatToTextsMiddle() { expectedTextList.add(TooltipTextUtil.createText(" in which any field contains the regular expression")); String test = "This search contains entries %0 in which any field contains the regular expression"; List textList = TooltipTextUtil.formatToTexts(test, new TooltipTextUtil.TextReplacement("%0", "replacing text", TooltipTextUtil.TextType.BOLD)); - Assert.assertTrue(TextFlowEqualityHelper.checkIfTextsEqualsExpectedTexts(expectedTextList, textList)); + assertTrue(TextFlowEqualityHelper.checkIfTextsEqualsExpectedTexts(expectedTextList, textList)); } } diff --git a/src/test/java/org/jabref/gui/worker/CitationStyleToClipboardWorkerTest.java b/src/test/java/org/jabref/gui/worker/CitationStyleToClipboardWorkerTest.java index bcd86e7817a..5b899af7beb 100644 --- a/src/test/java/org/jabref/gui/worker/CitationStyleToClipboardWorkerTest.java +++ b/src/test/java/org/jabref/gui/worker/CitationStyleToClipboardWorkerTest.java @@ -9,9 +9,9 @@ import org.jabref.gui.fieldeditors.XmlTransferable; import org.jabref.logic.util.OS; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; public class CitationStyleToClipboardWorkerTest { @@ -31,7 +31,7 @@ public void processPreviewText() throws Exception { HtmlTransferable HtmlTransferable = CitationStyleToClipboardWorker.processPreview(Arrays.asList(citation, citation)); Object actual = HtmlTransferable.getTransferData(DataFlavor.stringFlavor); - Assert.assertEquals(expected, actual); + assertEquals(expected, actual); } @Test @@ -84,7 +84,7 @@ public void processPreviewHtml() throws Exception { HtmlTransferable transferable = CitationStyleToClipboardWorker.processPreview(Arrays.asList(citation, citation)); Object actual = transferable.getTransferData(HtmlTransferable.HTML_FLAVOR); - Assert.assertEquals(expected, actual); + assertEquals(expected, actual); } @Test @@ -96,7 +96,7 @@ public void processText() throws Exception { StringSelection textTransferable = CitationStyleToClipboardWorker.processText(Arrays.asList(citation, citation)); Object actual = textTransferable.getTransferData(DataFlavor.stringFlavor); - Assert.assertEquals(expected, actual); + assertEquals(expected, actual); } @Test @@ -111,7 +111,7 @@ public void processRtf() throws Exception { RtfTransferable rtfTransferable = CitationStyleToClipboardWorker.processRtf(Arrays.asList(citation, citation)); Object actual = rtfTransferable.getTransferData(DataFlavor.stringFlavor); - Assert.assertEquals(expected, actual); + assertEquals(expected, actual); } @Test @@ -184,7 +184,7 @@ public void processXslFo() throws Exception { XmlTransferable xmlTransferable = CitationStyleToClipboardWorker.processXslFo(Arrays.asList(citation, citation)); Object actual = xmlTransferable.getTransferData(DataFlavor.stringFlavor); - Assert.assertEquals(expected, actual); + assertEquals(expected, actual); } @Test @@ -214,7 +214,7 @@ public void processHtmlAsHtml() throws Exception { HtmlTransferable htmlTransferable = CitationStyleToClipboardWorker.processHtml(Arrays.asList(citation, citation)); Object actual = htmlTransferable.getTransferData(DataFlavor.allHtmlFlavor); - Assert.assertEquals(expected, actual); + assertEquals(expected, actual); } @Test @@ -228,6 +228,6 @@ public void processHtmlAsText() throws Exception { HtmlTransferable htmlTransferable = CitationStyleToClipboardWorker.processHtml(Arrays.asList(citation, citation)); Object actual = htmlTransferable.getTransferData(DataFlavor.stringFlavor); - Assert.assertEquals(expected, actual); + assertEquals(expected, actual); } } diff --git a/src/test/java/org/jabref/logic/TypedBibEntryTest.java b/src/test/java/org/jabref/logic/TypedBibEntryTest.java index 517217b6152..8b72810ecc9 100644 --- a/src/test/java/org/jabref/logic/TypedBibEntryTest.java +++ b/src/test/java/org/jabref/logic/TypedBibEntryTest.java @@ -4,8 +4,11 @@ import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.BibtexEntryTypes; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; public class TypedBibEntryTest { @@ -17,7 +20,7 @@ public void hasAllRequiredFieldsFail() { e.setField("journal", "abc"); TypedBibEntry typedEntry = new TypedBibEntry(e, BibDatabaseMode.BIBTEX); - Assert.assertFalse(typedEntry.hasAllRequiredFields()); + assertFalse(typedEntry.hasAllRequiredFields()); } @Test @@ -29,7 +32,7 @@ public void hasAllRequiredFields() { e.setField("year", "2015"); TypedBibEntry typedEntry = new TypedBibEntry(e, BibDatabaseMode.BIBTEX); - Assert.assertTrue(typedEntry.hasAllRequiredFields()); + assertTrue(typedEntry.hasAllRequiredFields()); } @Test @@ -37,7 +40,7 @@ public void hasAllRequiredFieldsForUnknownTypeReturnsTrue() { BibEntry e = new BibEntry("articlllleeeee"); TypedBibEntry typedEntry = new TypedBibEntry(e, BibDatabaseMode.BIBTEX); - Assert.assertTrue(typedEntry.hasAllRequiredFields()); + assertTrue(typedEntry.hasAllRequiredFields()); } @Test @@ -45,7 +48,7 @@ public void getTypeForDisplayReturnsTypeName() { BibEntry e = new BibEntry(BibtexEntryTypes.INPROCEEDINGS.getName()); TypedBibEntry typedEntry = new TypedBibEntry(e, BibDatabaseMode.BIBTEX); - Assert.assertEquals("InProceedings", typedEntry.getTypeForDisplay()); + assertEquals("InProceedings", typedEntry.getTypeForDisplay()); } @Test @@ -53,6 +56,6 @@ public void getTypeForDisplayForUnknownTypeCapitalizeFirstLetter() { BibEntry e = new BibEntry("articlllleeeee"); TypedBibEntry typedEntry = new TypedBibEntry(e, BibDatabaseMode.BIBTEX); - Assert.assertEquals("Articlllleeeee", typedEntry.getTypeForDisplay()); + assertEquals("Articlllleeeee", typedEntry.getTypeForDisplay()); } } diff --git a/src/test/java/org/jabref/logic/autosaveandbackup/BackupManagerTest.java b/src/test/java/org/jabref/logic/autosaveandbackup/BackupManagerTest.java index 3abd3b6e69d..744682b6f9c 100644 --- a/src/test/java/org/jabref/logic/autosaveandbackup/BackupManagerTest.java +++ b/src/test/java/org/jabref/logic/autosaveandbackup/BackupManagerTest.java @@ -3,8 +3,9 @@ import java.nio.file.Path; import java.nio.file.Paths; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; public class BackupManagerTest { @@ -12,7 +13,7 @@ public class BackupManagerTest { public void backupFileNameIsCorrectlyGeneratedWithinTmpDirectory() { Path bibPath = Paths.get("tmp", "test.bib"); Path savPath = BackupManager.getBackupPath(bibPath); - Assert.assertEquals(Paths.get("tmp", "test.bib.sav"), savPath); + assertEquals(Paths.get("tmp", "test.bib.sav"), savPath); } } diff --git a/src/test/java/org/jabref/logic/auxparser/AuxParserTest.java b/src/test/java/org/jabref/logic/auxparser/AuxParserTest.java index 016f7b62d26..bc75d7d7f89 100644 --- a/src/test/java/org/jabref/logic/auxparser/AuxParserTest.java +++ b/src/test/java/org/jabref/logic/auxparser/AuxParserTest.java @@ -19,7 +19,7 @@ import org.junit.After; import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.mockito.Answers; import static org.junit.Assert.assertEquals; diff --git a/src/test/java/org/jabref/logic/bibtex/FieldContentParserTest.java b/src/test/java/org/jabref/logic/bibtex/FieldContentParserTest.java index c4530f03533..0c973a6aed2 100644 --- a/src/test/java/org/jabref/logic/bibtex/FieldContentParserTest.java +++ b/src/test/java/org/jabref/logic/bibtex/FieldContentParserTest.java @@ -4,17 +4,17 @@ import org.jabref.logic.util.OS; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class FieldContentParserTest { private FieldContentParser parser; private FieldContentParserPreferences prefs; - @Before + @BeforeEach public void setUp() throws Exception { prefs = new FieldContentParserPreferences(Collections.emptyList()); parser = new FieldContentParser(prefs); diff --git a/src/test/java/org/jabref/logic/bibtex/LatexFieldFormatterTests.java b/src/test/java/org/jabref/logic/bibtex/LatexFieldFormatterTests.java index c9c6c7ce63f..7b822bb1b98 100644 --- a/src/test/java/org/jabref/logic/bibtex/LatexFieldFormatterTests.java +++ b/src/test/java/org/jabref/logic/bibtex/LatexFieldFormatterTests.java @@ -4,18 +4,19 @@ import org.jabref.logic.util.OS; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.mockito.Answers; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.Mockito.mock; public class LatexFieldFormatterTests { private LatexFieldFormatter formatter; - @Before + @BeforeEach public void setUp() { this.formatter = new LatexFieldFormatter(mock(LatexFieldFormatterPreferences.class, Answers.RETURNS_DEEP_STUBS)); } @@ -85,18 +86,16 @@ public void removeWhitespaceFromNonMultiLineFields() throws Exception { assertEquals(expected, any); } - @Test(expected = InvalidFieldValueException.class) public void reportUnbalancedBracing() throws Exception { String unbalanced = "{"; - formatter.format(unbalanced, "anyfield"); + assertThrows(InvalidFieldValueException.class, () -> formatter.format(unbalanced, "anyfield")); } - @Test(expected = InvalidFieldValueException.class) public void reportUnbalancedBracingWithEscapedBraces() throws Exception { String unbalanced = "{\\}"; - formatter.format(unbalanced, "anyfield"); + assertThrows(InvalidFieldValueException.class, () -> formatter.format(unbalanced, "anyfield")); } @Test diff --git a/src/test/java/org/jabref/logic/bibtex/comparator/BibDatabaseDiffTest.java b/src/test/java/org/jabref/logic/bibtex/comparator/BibDatabaseDiffTest.java index 83ea84a5863..cdf7115824c 100644 --- a/src/test/java/org/jabref/logic/bibtex/comparator/BibDatabaseDiffTest.java +++ b/src/test/java/org/jabref/logic/bibtex/comparator/BibDatabaseDiffTest.java @@ -5,11 +5,12 @@ import org.jabref.model.database.BibDatabaseContext; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class BibDatabaseDiffTest { + @Test public void compareOfEmptyDatabasesReportsNoDifferences() throws Exception { BibDatabaseDiff diff = BibDatabaseDiff.compare(new BibDatabaseContext(), new BibDatabaseContext()); diff --git a/src/test/java/org/jabref/logic/bibtex/comparator/BibtexStringComparatorTest.java b/src/test/java/org/jabref/logic/bibtex/comparator/BibtexStringComparatorTest.java index 3130258f888..9a6d3bbbb26 100644 --- a/src/test/java/org/jabref/logic/bibtex/comparator/BibtexStringComparatorTest.java +++ b/src/test/java/org/jabref/logic/bibtex/comparator/BibtexStringComparatorTest.java @@ -2,10 +2,10 @@ import org.jabref.model.entry.BibtexString; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; public class BibtexStringComparatorTest { diff --git a/src/test/java/org/jabref/logic/bibtex/comparator/CrossRefEntryComparatorTest.java b/src/test/java/org/jabref/logic/bibtex/comparator/CrossRefEntryComparatorTest.java index f7cb609f03c..2e084da5b5e 100644 --- a/src/test/java/org/jabref/logic/bibtex/comparator/CrossRefEntryComparatorTest.java +++ b/src/test/java/org/jabref/logic/bibtex/comparator/CrossRefEntryComparatorTest.java @@ -3,21 +3,21 @@ import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.FieldName; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class CrossRefEntryComparatorTest { private CrossRefEntryComparator comparator; - @Before + @BeforeEach public void setUp() { comparator = new CrossRefEntryComparator(); } - @After + @AfterEach public void tearDown() { comparator = null; } diff --git a/src/test/java/org/jabref/logic/bibtex/comparator/EntryComparatorTest.java b/src/test/java/org/jabref/logic/bibtex/comparator/EntryComparatorTest.java index c7a6f73b315..3e7dbd346da 100644 --- a/src/test/java/org/jabref/logic/bibtex/comparator/EntryComparatorTest.java +++ b/src/test/java/org/jabref/logic/bibtex/comparator/EntryComparatorTest.java @@ -2,7 +2,7 @@ import org.jabref.model.entry.BibEntry; -import org.junit.Test; +import org.junit.jupiter.api.Test; import static org.junit.Assert.assertEquals; diff --git a/src/test/java/org/jabref/logic/bibtex/comparator/FieldComparatorTest.java b/src/test/java/org/jabref/logic/bibtex/comparator/FieldComparatorTest.java index a33f77a0edc..80742aff2ab 100644 --- a/src/test/java/org/jabref/logic/bibtex/comparator/FieldComparatorTest.java +++ b/src/test/java/org/jabref/logic/bibtex/comparator/FieldComparatorTest.java @@ -2,9 +2,9 @@ import org.jabref.model.entry.BibEntry; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class FieldComparatorTest { @Test diff --git a/src/test/java/org/jabref/logic/bibtex/comparator/MetaDataDiffTest.java b/src/test/java/org/jabref/logic/bibtex/comparator/MetaDataDiffTest.java index e70035009c2..38c9b152f61 100644 --- a/src/test/java/org/jabref/logic/bibtex/comparator/MetaDataDiffTest.java +++ b/src/test/java/org/jabref/logic/bibtex/comparator/MetaDataDiffTest.java @@ -5,9 +5,9 @@ import org.jabref.model.metadata.ContentSelector; import org.jabref.model.metadata.MetaData; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class MetaDataDiffTest { @Test diff --git a/src/test/java/org/jabref/logic/bibtexkeypattern/BibtexKeyGeneratorTest.java b/src/test/java/org/jabref/logic/bibtexkeypattern/BibtexKeyGeneratorTest.java index b855f9bc6d9..65a4e850b58 100644 --- a/src/test/java/org/jabref/logic/bibtexkeypattern/BibtexKeyGeneratorTest.java +++ b/src/test/java/org/jabref/logic/bibtexkeypattern/BibtexKeyGeneratorTest.java @@ -11,12 +11,12 @@ import org.jabref.model.util.DummyFileUpdateMonitor; import org.jabref.model.util.FileUpdateMonitor; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.mockito.Answers; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.Mockito.mock; public class BibtexKeyGeneratorTest { @@ -44,9 +44,9 @@ public class BibtexKeyGeneratorTest { private static final String TITLE_STRING_CASED_FOUR_SMALL_WORDS_TWO_CONNECTED_WORDS = "On the Measurement of Design-Time Adaptability for Process-Based Systems "; private static ImportFormatPreferences importFormatPreferences; - private FileUpdateMonitor fileMonitor = new DummyFileUpdateMonitor(); + private final FileUpdateMonitor fileMonitor = new DummyFileUpdateMonitor(); - @Before + @BeforeEach public void setUp() { importFormatPreferences = mock(ImportFormatPreferences.class, Answers.RETURNS_DEEP_STUBS); } @@ -301,9 +301,8 @@ public void testFirstAuthor() { assertEquals("", BibtexKeyGenerator.firstAuthor("")); } - @Test(expected = NullPointerException.class) public void testFirstAuthorNull() { - BibtexKeyGenerator.firstAuthor(null); + assertThrows(NullPointerException.class, () -> BibtexKeyGenerator.firstAuthor(null)); } @Test @@ -425,9 +424,8 @@ public void testAuthIniN() { assertEquals("Newton", BibtexKeyGenerator.authIniN(AUTHOR_STRING_FIRSTNAME_INITIAL_LASTNAME_FULL_COUNT_1, 7)); } - @Test(expected = NullPointerException.class) public void testAuthIniNNull() { - BibtexKeyGenerator.authIniN(null, 3); + assertThrows(NullPointerException.class, () -> BibtexKeyGenerator.authIniN(null, 3)); } @Test @@ -516,9 +514,8 @@ public void authNM() { assertEquals("", BibtexKeyGenerator.authNofMth("", 2, 4)); } - @Test(expected = NullPointerException.class) public void authNMThrowsNPE() { - BibtexKeyGenerator.authNofMth(null, 2, 4); + assertThrows(NullPointerException.class, () -> BibtexKeyGenerator.authNofMth(null, 2, 4)); } /** @@ -690,9 +687,8 @@ public void testFirstPage() { assertEquals("43", BibtexKeyGenerator.firstPage("43+")); } - @Test(expected = NullPointerException.class) public void testFirstPageNull() { - BibtexKeyGenerator.firstPage(null); + assertThrows(NullPointerException.class, () -> BibtexKeyGenerator.firstPage(null)); } @Test @@ -713,9 +709,8 @@ public void testPagePrefix() { assertEquals("", BibtexKeyGenerator.pagePrefix("43+")); } - @Test(expected = NullPointerException.class) public void testPagePrefixNull() { - BibtexKeyGenerator.pagePrefix(null); + assertThrows(NullPointerException.class, () -> BibtexKeyGenerator.pagePrefix(null)); } @Test @@ -730,9 +725,8 @@ public void testLastPage() { assertEquals("43", BibtexKeyGenerator.lastPage("43+")); } - @Test(expected = NullPointerException.class) public void testLastPageNull() { - BibtexKeyGenerator.lastPage(null); + assertThrows(NullPointerException.class, () -> BibtexKeyGenerator.lastPage(null)); } /** @@ -930,10 +924,10 @@ public void testCheckLegalKeyDoNotEnforceLegal() { assertEquals("", BibtexKeyGenerator.cleanKey("\n\t\r", false)); } - @Test(expected = NullPointerException.class) + @Test public void testCheckLegalNullInNullOut() { - assertNull(BibtexKeyGenerator.cleanKey(null, true)); - assertNull(BibtexKeyGenerator.cleanKey(null, false)); + assertThrows(NullPointerException.class, () -> BibtexKeyGenerator.cleanKey(null, true)); + assertThrows(NullPointerException.class, () -> BibtexKeyGenerator.cleanKey(null, false)); } @Test diff --git a/src/test/java/org/jabref/logic/bibtexkeypattern/MakeLabelWithDatabaseTest.java b/src/test/java/org/jabref/logic/bibtexkeypattern/MakeLabelWithDatabaseTest.java index 38880288509..345d568ff5d 100644 --- a/src/test/java/org/jabref/logic/bibtexkeypattern/MakeLabelWithDatabaseTest.java +++ b/src/test/java/org/jabref/logic/bibtexkeypattern/MakeLabelWithDatabaseTest.java @@ -7,8 +7,8 @@ import org.jabref.model.database.BibDatabase; import org.jabref.model.entry.BibEntry; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import static org.junit.Assert.assertEquals; @@ -20,7 +20,7 @@ public class MakeLabelWithDatabaseTest { private DatabaseBibtexKeyPattern bibtexKeyPattern; private BibEntry entry; - @Before + @BeforeEach public void setUp() { database = new BibDatabase(); diff --git a/src/test/java/org/jabref/logic/bibtexkeypattern/MakeLabelWithoutDatabaseTest.java b/src/test/java/org/jabref/logic/bibtexkeypattern/MakeLabelWithoutDatabaseTest.java index 88af32ce21b..72d9d0d3dcc 100644 --- a/src/test/java/org/jabref/logic/bibtexkeypattern/MakeLabelWithoutDatabaseTest.java +++ b/src/test/java/org/jabref/logic/bibtexkeypattern/MakeLabelWithoutDatabaseTest.java @@ -2,8 +2,8 @@ import org.jabref.model.entry.BibEntry; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import static org.junit.Assert.assertEquals; @@ -11,7 +11,7 @@ public class MakeLabelWithoutDatabaseTest { private BibEntry entry; - @Before + @BeforeEach public void setUp() { entry = new BibEntry(); entry.setField("author", "John Doe"); diff --git a/src/test/java/org/jabref/logic/bst/BibtexCaseChangersTest.java b/src/test/java/org/jabref/logic/bst/BibtexCaseChangersTest.java index 11e99127127..a6214a7f0c8 100644 --- a/src/test/java/org/jabref/logic/bst/BibtexCaseChangersTest.java +++ b/src/test/java/org/jabref/logic/bst/BibtexCaseChangersTest.java @@ -2,8 +2,9 @@ import org.jabref.logic.bst.BibtexCaseChanger.FORMAT_MODE; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; public class BibtexCaseChangersTest { @@ -121,15 +122,15 @@ public void testTitleCase() { } private void assertCaseChangerTitleLowers(final String string, final String string2) { - Assert.assertEquals(string, BibtexCaseChanger.changeCase(string2, FORMAT_MODE.TITLE_LOWERS)); + assertEquals(string, BibtexCaseChanger.changeCase(string2, FORMAT_MODE.TITLE_LOWERS)); } private void assertCaseChangerAllLowers(final String string, final String string2) { - Assert.assertEquals(string, BibtexCaseChanger.changeCase(string2, FORMAT_MODE.ALL_LOWERS)); + assertEquals(string, BibtexCaseChanger.changeCase(string2, FORMAT_MODE.ALL_LOWERS)); } private void assertCaseChangerAllUppers(final String string, final String string2) { - Assert.assertEquals(string, BibtexCaseChanger.changeCase(string2, FORMAT_MODE.ALL_UPPERS)); + assertEquals(string, BibtexCaseChanger.changeCase(string2, FORMAT_MODE.ALL_UPPERS)); } } diff --git a/src/test/java/org/jabref/logic/bst/BibtexNameFormatterTest.java b/src/test/java/org/jabref/logic/bst/BibtexNameFormatterTest.java index 63ff8ddae22..8fd58e42ff1 100644 --- a/src/test/java/org/jabref/logic/bst/BibtexNameFormatterTest.java +++ b/src/test/java/org/jabref/logic/bst/BibtexNameFormatterTest.java @@ -2,8 +2,10 @@ import org.jabref.model.entry.AuthorList; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; public class BibtexNameFormatterTest { @@ -13,32 +15,31 @@ public void testFormatName() { AuthorList al = AuthorList .parse("Charles Louis Xavier Joseph de la Vall{\\'e}e Poussin"); - Assert.assertEquals("de~laVall{\\'e}e~PoussinCharles Louis Xavier~Joseph", BibtexNameFormatter.formatName(al - .getAuthor(0), "{vv}{ll}{jj}{ff}", Assert::fail)); + assertEquals("de~laVall{\\'e}e~PoussinCharles Louis Xavier~Joseph", BibtexNameFormatter.formatName(al + .getAuthor(0), "{vv}{ll}{jj}{ff}", Assertions::fail)); } { AuthorList al = AuthorList .parse("Charles Louis Xavier Joseph de la Vall{\\'e}e Poussin"); - Assert.assertEquals("de~la Vall{\\'e}e~Poussin, C.~L. X.~J.", BibtexNameFormatter.formatName(al - .getAuthor(0), "{vv~}{ll}{, jj}{, f.}", Assert::fail)); + assertEquals("de~la Vall{\\'e}e~Poussin, C.~L. X.~J.", BibtexNameFormatter.formatName(al + .getAuthor(0), "{vv~}{ll}{, jj}{, f.}", Assertions::fail)); } { AuthorList al = AuthorList .parse("Charles Louis Xavier Joseph de la Vall{\\'e}e Poussin"); - Assert.assertEquals("de~la Vall{\\'e}e~Poussin, C.~L. X.~J?", BibtexNameFormatter.formatName(al - .getAuthor(0), "{vv~}{ll}{, jj}{, f}?", Assert::fail)); + assertEquals("de~la Vall{\\'e}e~Poussin, C.~L. X.~J?", BibtexNameFormatter.formatName(al + .getAuthor(0), "{vv~}{ll}{, jj}{, f}?", Assertions::fail)); } AuthorList al = AuthorList .parse("Charles Louis Xavier Joseph de la Vall{\\'e}e Poussin"); - Assert.assertEquals("dlVP", BibtexNameFormatter.formatName(al.getAuthor(0), "{v{}}{l{}}", - Assert::fail - )); + assertEquals("dlVP", BibtexNameFormatter.formatName(al.getAuthor(0), "{v{}}{l{}}", + Assertions::fail)); assertNameFormatA("Meyer, J?", "Jonathan Meyer and Charles Louis Xavier Joseph de la Vall{\\'e}e Poussin"); assertNameFormatB("J.~Meyer", "Jonathan Meyer and Charles Louis Xavier Joseph de la Vall{\\'e}e Poussin"); @@ -57,9 +58,8 @@ public void testFormatName() { } private void assertNameFormat(String string, String string2, int which, String format) { - Assert.assertEquals(string, BibtexNameFormatter.formatName(string2, which, format, - Assert::fail - )); + assertEquals(string, BibtexNameFormatter.formatName(string2, which, format, + Assertions::fail)); } private void assertNameFormatC(String string, String string2) { @@ -78,41 +78,41 @@ private void assertNameFormatA(String string, String string2) { public void testConsumeToMatchingBrace() { { StringBuilder sb = new StringBuilder(); - Assert.assertEquals(6, BibtexNameFormatter.consumeToMatchingBrace(sb, "{HELLO} {WORLD}" + assertEquals(6, BibtexNameFormatter.consumeToMatchingBrace(sb, "{HELLO} {WORLD}" .toCharArray(), 0)); - Assert.assertEquals("{HELLO}", sb.toString()); + assertEquals("{HELLO}", sb.toString()); } { StringBuilder sb = new StringBuilder(); - Assert.assertEquals(18, BibtexNameFormatter.consumeToMatchingBrace(sb, "{HE{L{}L}O} {WORLD}" + assertEquals(18, BibtexNameFormatter.consumeToMatchingBrace(sb, "{HE{L{}L}O} {WORLD}" .toCharArray(), 12)); - Assert.assertEquals("{WORLD}", sb.toString()); + assertEquals("{WORLD}", sb.toString()); } StringBuilder sb = new StringBuilder(); - Assert.assertEquals(10, BibtexNameFormatter.consumeToMatchingBrace(sb, "{HE{L{}L}O} {WORLD}" + assertEquals(10, BibtexNameFormatter.consumeToMatchingBrace(sb, "{HE{L{}L}O} {WORLD}" .toCharArray(), 0)); - Assert.assertEquals("{HE{L{}L}O}", sb.toString()); + assertEquals("{HE{L{}L}O}", sb.toString()); } @Test public void testGetFirstCharOfString() { - Assert.assertEquals("C", BibtexNameFormatter.getFirstCharOfString("Charles")); - Assert.assertEquals("V", BibtexNameFormatter.getFirstCharOfString("Vall{\\'e}e")); - Assert.assertEquals("{\\'e}", BibtexNameFormatter.getFirstCharOfString("{\\'e}")); - Assert.assertEquals("{\\'e", BibtexNameFormatter.getFirstCharOfString("{\\'e")); - Assert.assertEquals("E", BibtexNameFormatter.getFirstCharOfString("{E")); + assertEquals("C", BibtexNameFormatter.getFirstCharOfString("Charles")); + assertEquals("V", BibtexNameFormatter.getFirstCharOfString("Vall{\\'e}e")); + assertEquals("{\\'e}", BibtexNameFormatter.getFirstCharOfString("{\\'e}")); + assertEquals("{\\'e", BibtexNameFormatter.getFirstCharOfString("{\\'e")); + assertEquals("E", BibtexNameFormatter.getFirstCharOfString("{E")); } @Test public void testNumberOfChars() { - Assert.assertEquals(6, BibtexNameFormatter.numberOfChars("Vall{\\'e}e", -1)); - Assert.assertEquals(2, BibtexNameFormatter.numberOfChars("Vall{\\'e}e", 2)); - Assert.assertEquals(1, BibtexNameFormatter.numberOfChars("Vall{\\'e}e", 1)); - Assert.assertEquals(6, BibtexNameFormatter.numberOfChars("Vall{\\'e}e", 6)); - Assert.assertEquals(6, BibtexNameFormatter.numberOfChars("Vall{\\'e}e", 7)); - Assert.assertEquals(8, BibtexNameFormatter.numberOfChars("Vall{e}e", -1)); - Assert.assertEquals(6, BibtexNameFormatter.numberOfChars("Vall{\\'e this will be skipped}e", -1)); + assertEquals(6, BibtexNameFormatter.numberOfChars("Vall{\\'e}e", -1)); + assertEquals(2, BibtexNameFormatter.numberOfChars("Vall{\\'e}e", 2)); + assertEquals(1, BibtexNameFormatter.numberOfChars("Vall{\\'e}e", 1)); + assertEquals(6, BibtexNameFormatter.numberOfChars("Vall{\\'e}e", 6)); + assertEquals(6, BibtexNameFormatter.numberOfChars("Vall{\\'e}e", 7)); + assertEquals(8, BibtexNameFormatter.numberOfChars("Vall{e}e", -1)); + assertEquals(6, BibtexNameFormatter.numberOfChars("Vall{\\'e this will be skipped}e", -1)); } } diff --git a/src/test/java/org/jabref/logic/bst/BibtexPurifyTest.java b/src/test/java/org/jabref/logic/bst/BibtexPurifyTest.java index 8a9760f7ba7..799a4d572ba 100644 --- a/src/test/java/org/jabref/logic/bst/BibtexPurifyTest.java +++ b/src/test/java/org/jabref/logic/bst/BibtexPurifyTest.java @@ -1,7 +1,9 @@ package org.jabref.logic.bst; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; public class BibtexPurifyTest { @@ -19,7 +21,6 @@ public void testPurify() { } private void assertPurify(final String string, final String string2) { - Assert.assertEquals(string, BibtexPurify.purify(string2, s -> - Assert.fail("Should not Warn (" + s + ")! purify should be " + string + " for " + string2))); + assertEquals(string, BibtexPurify.purify(string2, s -> fail("Should not Warn (" + s + ")! purify should be " + string + " for " + string2))); } } diff --git a/src/test/java/org/jabref/logic/bst/BibtexWidthTest.java b/src/test/java/org/jabref/logic/bst/BibtexWidthTest.java index 19e671f867d..5d64a2a7b74 100644 --- a/src/test/java/org/jabref/logic/bst/BibtexWidthTest.java +++ b/src/test/java/org/jabref/logic/bst/BibtexWidthTest.java @@ -1,8 +1,9 @@ package org.jabref.logic.bst; -import org.junit.Assert; import org.junit.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; + /** * How to create these test using Bibtex: *

@@ -33,7 +34,7 @@ public class BibtexWidthTest { private void assertBibtexWidth(final int i, final String string) { - Assert.assertEquals(i, BibtexWidth.width(string)); + assertEquals(i, BibtexWidth.width(string)); } @Test @@ -61,10 +62,10 @@ public void testWidth() { @Test public void testGetCharWidth() { - Assert.assertEquals(500, BibtexWidth.getCharWidth('0')); - Assert.assertEquals(361, BibtexWidth.getCharWidth('I')); - Assert.assertEquals(500, BibtexWidth.getCharWidth('~')); - Assert.assertEquals(500, BibtexWidth.getCharWidth('}')); - Assert.assertEquals(278, BibtexWidth.getCharWidth(' ')); + assertEquals(500, BibtexWidth.getCharWidth('0')); + assertEquals(361, BibtexWidth.getCharWidth('I')); + assertEquals(500, BibtexWidth.getCharWidth('~')); + assertEquals(500, BibtexWidth.getCharWidth('}')); + assertEquals(278, BibtexWidth.getCharWidth(' ')); } } diff --git a/src/test/java/org/jabref/logic/bst/TestVM.java b/src/test/java/org/jabref/logic/bst/TestVM.java index 92f875466ed..a1e853b8c83 100644 --- a/src/test/java/org/jabref/logic/bst/TestVM.java +++ b/src/test/java/org/jabref/logic/bst/TestVM.java @@ -17,15 +17,16 @@ import org.jabref.model.util.DummyFileUpdateMonitor; import org.antlr.runtime.RecognitionException; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.mockito.Answers; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; import static org.mockito.Mockito.mock; public class TestVM { - @Test public void testAbbrv() throws RecognitionException, IOException { VM vm = new VM(new File("src/test/resources/org/jabref/logic/bst/abbrv.bst")); @@ -34,7 +35,7 @@ public void testAbbrv() throws RecognitionException, IOException { String expected = "\\begin{thebibliography}{1}\\bibitem{canh05}K.~Crowston, H.~Annabi, J.~Howison, and C.~Masango.\\newblock Effective work practices for floss development: A model and propositions.\\newblock In {\\em Hawaii International Conference On System Sciences (HICSS)}, 2005.\\end{thebibliography}"; - Assert.assertEquals(expected.replaceAll("\\s", ""), vm.run(v).replaceAll("\\s", "")); + assertEquals(expected.replaceAll("\\s", ""), vm.run(v).replaceAll("\\s", "")); } @Test @@ -52,11 +53,11 @@ public void testVMSimple() throws RecognitionException, IOException { vm.run(v); - Assert.assertEquals(2, vm.getStrings().size()); - Assert.assertEquals(7, vm.getIntegers().size()); - Assert.assertEquals(1, vm.getEntries().size()); - Assert.assertEquals(5, vm.getEntries().get(0).getFields().size()); - Assert.assertEquals(38, vm.getFunctions().size()); + assertEquals(2, vm.getStrings().size()); + assertEquals(7, vm.getIntegers().size()); + assertEquals(1, vm.getEntries().size()); + assertEquals(5, vm.getEntries().get(0).getFields().size()); + assertEquals(38, vm.getFunctions().size()); } @@ -72,8 +73,9 @@ public void testLabel() throws RecognitionException, IOException { vm.run(v); - Assert.assertEquals("Effective work practices for floss development: A model and propositions", vm - .getStack().pop()); + assertEquals("Effective work practices for floss development: A model and propositions", vm + .getStack() + .pop()); } @@ -85,7 +87,7 @@ public void testQuote() throws RecognitionException { List v = new ArrayList<>(); vm.run(v); - Assert.assertEquals("\"\"", vm.getStack().pop()); + assertEquals("\"\"", vm.getStack().pop()); } @Test @@ -96,12 +98,12 @@ public void testVMFunction1() throws RecognitionException { List v = new ArrayList<>(); vm.run(v); - Assert.assertEquals(38, vm.getFunctions().size()); + assertEquals(38, vm.getFunctions().size()); - Assert.assertTrue(vm.getFunctions().get("init.state.consts") instanceof StackFunction); + assertTrue(vm.getFunctions().get("init.state.consts") instanceof StackFunction); StackFunction fun = (StackFunction) vm.getFunctions().get("init.state.consts"); - Assert.assertEquals(3, fun.getTree().getChildCount()); + assertEquals(3, fun.getTree().getChildCount()); } @Test @@ -111,7 +113,7 @@ public void testVMExecuteSimple() throws RecognitionException { List v = new ArrayList<>(); vm.run(v); - Assert.assertEquals(Integer.valueOf(5), vm.getIntegers().get("variable.a")); + assertEquals(Integer.valueOf(5), vm.getIntegers().get("variable.a")); } @Test @@ -123,17 +125,17 @@ public void testVMExecuteSimple2() throws RecognitionException { List v = new ArrayList<>(); vm.run(v); - Assert.assertEquals(VM.FALSE, vm.getStack().pop()); - Assert.assertEquals(VM.TRUE, vm.getStack().pop()); - Assert.assertEquals(VM.FALSE, vm.getStack().pop()); - Assert.assertEquals(VM.TRUE, vm.getStack().pop()); - Assert.assertEquals(VM.FALSE, vm.getStack().pop()); - Assert.assertEquals(VM.FALSE, vm.getStack().pop()); - Assert.assertEquals(VM.FALSE, vm.getStack().pop()); - Assert.assertEquals(VM.TRUE, vm.getStack().pop()); - Assert.assertEquals(VM.FALSE, vm.getStack().pop()); - Assert.assertEquals(VM.TRUE, vm.getStack().pop()); - Assert.assertEquals(0, vm.getStack().size()); + assertEquals(VM.FALSE, vm.getStack().pop()); + assertEquals(VM.TRUE, vm.getStack().pop()); + assertEquals(VM.FALSE, vm.getStack().pop()); + assertEquals(VM.TRUE, vm.getStack().pop()); + assertEquals(VM.FALSE, vm.getStack().pop()); + assertEquals(VM.FALSE, vm.getStack().pop()); + assertEquals(VM.FALSE, vm.getStack().pop()); + assertEquals(VM.TRUE, vm.getStack().pop()); + assertEquals(VM.FALSE, vm.getStack().pop()); + assertEquals(VM.TRUE, vm.getStack().pop()); + assertEquals(0, vm.getStack().size()); } @Test @@ -146,17 +148,17 @@ public void testVMIfSkipPop() throws RecognitionException { List v = new ArrayList<>(); vm.run(v); - Assert.assertEquals(VM.FALSE, vm.getStack().pop()); - Assert.assertEquals(VM.TRUE, vm.getStack().pop()); - Assert.assertEquals(VM.TRUE, vm.getStack().pop()); - Assert.assertEquals(VM.TRUE, vm.getStack().pop()); - Assert.assertEquals(VM.FALSE, vm.getStack().pop()); - Assert.assertEquals(VM.TRUE, vm.getStack().pop()); - Assert.assertEquals(VM.FALSE, vm.getStack().pop()); - Assert.assertEquals(VM.FALSE, vm.getStack().pop()); - Assert.assertEquals(VM.FALSE, vm.getStack().pop()); - Assert.assertEquals(VM.TRUE, vm.getStack().pop()); - Assert.assertEquals(0, vm.getStack().size()); + assertEquals(VM.FALSE, vm.getStack().pop()); + assertEquals(VM.TRUE, vm.getStack().pop()); + assertEquals(VM.TRUE, vm.getStack().pop()); + assertEquals(VM.TRUE, vm.getStack().pop()); + assertEquals(VM.FALSE, vm.getStack().pop()); + assertEquals(VM.TRUE, vm.getStack().pop()); + assertEquals(VM.FALSE, vm.getStack().pop()); + assertEquals(VM.FALSE, vm.getStack().pop()); + assertEquals(VM.FALSE, vm.getStack().pop()); + assertEquals(VM.TRUE, vm.getStack().pop()); + assertEquals(0, vm.getStack().size()); } @Test @@ -166,12 +168,11 @@ public void testVMArithmetic() throws RecognitionException { List v = new ArrayList<>(); vm.run(v); - Assert.assertEquals(3, vm.getStack().pop()); - Assert.assertEquals(2, vm.getStack().pop()); - Assert.assertEquals(0, vm.getStack().size()); + assertEquals(3, vm.getStack().pop()); + assertEquals(2, vm.getStack().pop()); + assertEquals(0, vm.getStack().size()); } - @Test public void testVMArithmetic2() throws RecognitionException { VM vm = new VM("FUNCTION {test} { " + "#1 \"HELLO\" + #5 #2 - }" + "EXECUTE {test}"); @@ -180,7 +181,7 @@ public void testVMArithmetic2() throws RecognitionException { try { vm.run(v); - Assert.fail(); + fail("fail"); } catch (VMException ignored) { // Ignored } @@ -192,8 +193,8 @@ public void testNumNames() throws RecognitionException { List v = new ArrayList<>(); vm.run(v); - Assert.assertEquals(2, vm.getStack().pop()); - Assert.assertEquals(0, vm.getStack().size()); + assertEquals(2, vm.getStack().pop()); + assertEquals(0, vm.getStack().size()); } @Test @@ -203,8 +204,8 @@ public void testNumNames2() throws RecognitionException { List v = new ArrayList<>(); vm.run(v); - Assert.assertEquals(1, vm.getStack().pop()); - Assert.assertEquals(0, vm.getStack().size()); + assertEquals(1, vm.getStack().pop()); + assertEquals(0, vm.getStack().size()); } @Test @@ -213,70 +214,69 @@ public void testVMStringOps1() throws RecognitionException { "FUNCTION {test} { \"H\" \"allo\" * \"Johnny\" add.period$ \"Johnny.\" add.period$" + "\"Johnny!\" add.period$ \"Johnny?\" add.period$ \"Johnny} }}}\" add.period$" + "\"Johnny!}\" add.period$ \"Johnny?}\" add.period$ \"Johnny.}\" add.period$ }" - + "EXECUTE {test}" - ); + + "EXECUTE {test}"); List v = new ArrayList<>(); vm.run(v); - Assert.assertEquals("Johnny.}", vm.getStack().pop()); - Assert.assertEquals("Johnny?}", vm.getStack().pop()); - Assert.assertEquals("Johnny!}", vm.getStack().pop()); - Assert.assertEquals("Johnny.}", vm.getStack().pop()); - Assert.assertEquals("Johnny?", vm.getStack().pop()); - Assert.assertEquals("Johnny!", vm.getStack().pop()); - Assert.assertEquals("Johnny.", vm.getStack().pop()); - Assert.assertEquals("Johnny.", vm.getStack().pop()); - Assert.assertEquals("Hallo", vm.getStack().pop()); - Assert.assertEquals(0, vm.getStack().size()); + assertEquals("Johnny.}", vm.getStack().pop()); + assertEquals("Johnny?}", vm.getStack().pop()); + assertEquals("Johnny!}", vm.getStack().pop()); + assertEquals("Johnny.}", vm.getStack().pop()); + assertEquals("Johnny?", vm.getStack().pop()); + assertEquals("Johnny!", vm.getStack().pop()); + assertEquals("Johnny.", vm.getStack().pop()); + assertEquals("Johnny.", vm.getStack().pop()); + assertEquals("Hallo", vm.getStack().pop()); + assertEquals(0, vm.getStack().size()); } @Test public void testSubstring() throws RecognitionException { VM vm = new VM("FUNCTION {test} " + "{ \"123456789\" #2 #1 substring$ " + // 2 - " \"123456789\" #4 global.max$ substring$ " + // 456789 - " \"123456789\" #1 #9 substring$ " + // 123456789 - " \"123456789\" #1 #10 substring$ " + // 123456789 - " \"123456789\" #1 #99 substring$ " + // 123456789 + " \"123456789\" #4 global.max$ substring$ " + // 456789 + " \"123456789\" #1 #9 substring$ " + // 123456789 + " \"123456789\" #1 #10 substring$ " + // 123456789 + " \"123456789\" #1 #99 substring$ " + // 123456789 - " \"123456789\" #-7 #3 substring$ " + // 123 - " \"123456789\" #-1 #1 substring$ " + // 9 - " \"123456789\" #-1 #3 substring$ " + // 789 - " \"123456789\" #-2 #2 substring$ " + // 78 + " \"123456789\" #-7 #3 substring$ " + // 123 + " \"123456789\" #-1 #1 substring$ " + // 9 + " \"123456789\" #-1 #3 substring$ " + // 789 + " \"123456789\" #-2 #2 substring$ " + // 78 - "} EXECUTE {test} "); + "} EXECUTE {test} "); List v = new ArrayList<>(); vm.run(v); - Assert.assertEquals("78", vm.getStack().pop()); - Assert.assertEquals("789", vm.getStack().pop()); - Assert.assertEquals("9", vm.getStack().pop()); - Assert.assertEquals("123", vm.getStack().pop()); + assertEquals("78", vm.getStack().pop()); + assertEquals("789", vm.getStack().pop()); + assertEquals("9", vm.getStack().pop()); + assertEquals("123", vm.getStack().pop()); - Assert.assertEquals("123456789", vm.getStack().pop()); - Assert.assertEquals("123456789", vm.getStack().pop()); - Assert.assertEquals("123456789", vm.getStack().pop()); - Assert.assertEquals("456789", vm.getStack().pop()); - Assert.assertEquals("2", vm.getStack().pop()); - Assert.assertEquals(0, vm.getStack().size()); + assertEquals("123456789", vm.getStack().pop()); + assertEquals("123456789", vm.getStack().pop()); + assertEquals("123456789", vm.getStack().pop()); + assertEquals("456789", vm.getStack().pop()); + assertEquals("2", vm.getStack().pop()); + assertEquals(0, vm.getStack().size()); } @Test public void testEmpty() throws RecognitionException, IOException { VM vm = new VM("ENTRY {title}{}{} READ STRINGS { s } FUNCTION {test} " + "{ s empty$ " + // FALSE - "\"\" empty$ " + // FALSE - "\" \" empty$ " + // FALSE - " title empty$ " + // FALSE - " \" HALLO \" empty$ } ITERATE {test} "); + "\"\" empty$ " + // FALSE + "\" \" empty$ " + // FALSE + " title empty$ " + // FALSE + " \" HALLO \" empty$ } ITERATE {test} "); List v = new ArrayList<>(); v.add(TestVM.bibtexString2BibtexEntry("@article{a, author=\"AAA\"}")); vm.run(v); - Assert.assertEquals(VM.FALSE, vm.getStack().pop()); - Assert.assertEquals(VM.TRUE, vm.getStack().pop()); - Assert.assertEquals(VM.TRUE, vm.getStack().pop()); - Assert.assertEquals(VM.TRUE, vm.getStack().pop()); - Assert.assertEquals(VM.TRUE, vm.getStack().pop()); - Assert.assertEquals(0, vm.getStack().size()); + assertEquals(VM.FALSE, vm.getStack().pop()); + assertEquals(VM.TRUE, vm.getStack().pop()); + assertEquals(VM.TRUE, vm.getStack().pop()); + assertEquals(VM.TRUE, vm.getStack().pop()); + assertEquals(VM.TRUE, vm.getStack().pop()); + assertEquals(0, vm.getStack().size()); } @Test @@ -287,9 +287,9 @@ public void testDuplicateEmptyPopSwapIf() throws RecognitionException { List v = new ArrayList<>(); vm.run(v); - Assert.assertEquals("{\\em Hello}", vm.getStack().pop()); - Assert.assertEquals("", vm.getStack().pop()); - Assert.assertEquals(0, vm.getStack().size()); + assertEquals("{\\em Hello}", vm.getStack().pop()); + assertEquals("", vm.getStack().pop()); + assertEquals(0, vm.getStack().size()); } @Test @@ -308,18 +308,17 @@ public void testChangeCase() throws RecognitionException { + " \"Hello World\" format.title " + " \"\" format.title " + " \"{A}{D}/{C}ycle: {I}{B}{M}'s {F}ramework for {A}pplication {D}evelopment and {C}ase\" \"u\" change.case$ format.title " - + "}" + "EXECUTE {test} " - ); + + "}" + "EXECUTE {test} "); List v = new ArrayList<>(); vm.run(v); - Assert.assertEquals( + assertEquals( "{A}{D}/{C}ycle: {I}{B}{M}'s {F}ramework for {A}pplication {D}evelopment and {C}ase", vm.getStack().pop()); - Assert.assertEquals("", vm.getStack().pop()); - Assert.assertEquals("Hello world", vm.getStack().pop()); - Assert.assertEquals("Hello world", vm.getStack().pop()); - Assert.assertEquals(0, vm.getStack().size()); + assertEquals("", vm.getStack().pop()); + assertEquals("Hello world", vm.getStack().pop()); + assertEquals("Hello world", vm.getStack().pop()); + assertEquals(0, vm.getStack().size()); } @Test @@ -334,15 +333,15 @@ public void testTextLength() throws RecognitionException { List v = new ArrayList<>(); vm.run(v); - Assert.assertEquals(11, vm.getStack().pop()); - Assert.assertEquals(1, vm.getStack().pop()); - Assert.assertEquals(1, vm.getStack().pop()); - Assert.assertEquals(1, vm.getStack().pop()); - Assert.assertEquals(8, vm.getStack().pop()); - Assert.assertEquals(0, vm.getStack().pop()); - Assert.assertEquals(11, vm.getStack().pop()); - Assert.assertEquals(11, vm.getStack().pop()); - Assert.assertEquals(0, vm.getStack().size()); + assertEquals(11, vm.getStack().pop()); + assertEquals(1, vm.getStack().pop()); + assertEquals(1, vm.getStack().pop()); + assertEquals(1, vm.getStack().pop()); + assertEquals(8, vm.getStack().pop()); + assertEquals(0, vm.getStack().pop()); + assertEquals(11, vm.getStack().pop()); + assertEquals(11, vm.getStack().pop()); + assertEquals(0, vm.getStack().size()); } @Test @@ -351,9 +350,9 @@ public void testVMIntToStr() throws RecognitionException { List v = new ArrayList<>(); vm.run(v); - Assert.assertEquals("9999", vm.getStack().pop()); - Assert.assertEquals("3", vm.getStack().pop()); - Assert.assertEquals(0, vm.getStack().size()); + assertEquals("9999", vm.getStack().pop()); + assertEquals("3", vm.getStack().pop()); + assertEquals(0, vm.getStack().size()); } @Test @@ -362,8 +361,8 @@ public void testVMChrToInt() throws RecognitionException { List v = new ArrayList<>(); vm.run(v); - Assert.assertEquals(72, vm.getStack().pop()); - Assert.assertEquals(0, vm.getStack().size()); + assertEquals(72, vm.getStack().pop()); + assertEquals(0, vm.getStack().size()); } @Test @@ -372,8 +371,8 @@ public void testVMChrToIntIntToChr() throws RecognitionException { List v = new ArrayList<>(); vm.run(v); - Assert.assertEquals("H", vm.getStack().pop()); - Assert.assertEquals(0, vm.getStack().size()); + assertEquals("H", vm.getStack().pop()); + assertEquals(0, vm.getStack().size()); } @Test @@ -390,10 +389,10 @@ public void testSort() throws RecognitionException, IOException { vm.run(v); List v2 = vm.getEntries(); - Assert.assertEquals(Optional.of("a"), v2.get(0).getBibtexEntry().getCiteKeyOptional()); - Assert.assertEquals(Optional.of("b"), v2.get(1).getBibtexEntry().getCiteKeyOptional()); - Assert.assertEquals(Optional.of("c"), v2.get(2).getBibtexEntry().getCiteKeyOptional()); - Assert.assertEquals(Optional.of("d"), v2.get(3).getBibtexEntry().getCiteKeyOptional()); + assertEquals(Optional.of("a"), v2.get(0).getBibtexEntry().getCiteKeyOptional()); + assertEquals(Optional.of("b"), v2.get(1).getBibtexEntry().getCiteKeyOptional()); + assertEquals(Optional.of("c"), v2.get(2).getBibtexEntry().getCiteKeyOptional()); + assertEquals(Optional.of("d"), v2.get(3).getBibtexEntry().getCiteKeyOptional()); } @Test @@ -403,8 +402,8 @@ public void testBuildIn() throws RecognitionException { List v = new ArrayList<>(); vm.run(v); - Assert.assertEquals(Integer.MAX_VALUE, vm.getStack().pop()); - Assert.assertTrue(vm.getStack().empty()); + assertEquals(Integer.MAX_VALUE, vm.getStack().pop()); + assertTrue(vm.getStack().empty()); } @Test @@ -417,7 +416,7 @@ public void testVariables() throws RecognitionException { vm.run(new ArrayList<>()); - Assert.assertEquals(VM.TRUE, vm.getStack().pop()); + assertEquals(VM.TRUE, vm.getStack().pop()); } @Test @@ -452,22 +451,20 @@ public void testWhile() throws RecognitionException { + " } " + " while$ " + " } " - + " EXECUTE {n.dashify} " - ); + + " EXECUTE {n.dashify} "); List v = new ArrayList<>(); vm.run(v); - Assert.assertEquals(1, vm.getStack().size()); - Assert.assertEquals("HELLO--WORLD", vm.getStack().pop()); + assertEquals(1, vm.getStack().size()); + assertEquals("HELLO--WORLD", vm.getStack().pop()); } @Test public void testType() throws RecognitionException, IOException { VM vm = new VM("ENTRY { title } { } { label }" - + "FUNCTION {presort} { cite$ 'sort.key$ := } ITERATE { presort } SORT FUNCTION {test} { type$ } ITERATE { test }" - ); + + "FUNCTION {presort} { cite$ 'sort.key$ := } ITERATE { presort } SORT FUNCTION {test} { type$ } ITERATE { test }"); List v = new ArrayList<>(); v.add(TestVM.bibtexString2BibtexEntry("@article{a, author=\"AAA\"}")); @@ -476,11 +473,11 @@ public void testType() throws RecognitionException, IOException { v.add(TestVM.bibtexString2BibtexEntry("@inproceedings{d, author=\"DDD\"}")); vm.run(v); - Assert.assertEquals(4, vm.getStack().size()); - Assert.assertEquals("inproceedings", vm.getStack().pop()); - Assert.assertEquals("misc", vm.getStack().pop()); - Assert.assertEquals("book", vm.getStack().pop()); - Assert.assertEquals("article", vm.getStack().pop()); + assertEquals(4, vm.getStack().size()); + assertEquals("inproceedings", vm.getStack().pop()); + assertEquals("misc", vm.getStack().pop()); + assertEquals("book", vm.getStack().pop()); + assertEquals("article", vm.getStack().pop()); } @Test @@ -488,24 +485,23 @@ public void testMissing() throws RecognitionException, IOException { VM vm = new VM( // "ENTRY { title } { } { label } " + // - "FUNCTION {presort} { cite$ 'sort.key$ := } " + // - "ITERATE {presort} " + // - "READ SORT " + // - "FUNCTION {test}{ title missing$ cite$ } " + // - "ITERATE { test }" - ); + "FUNCTION {presort} { cite$ 'sort.key$ := } " + // + "ITERATE {presort} " + // + "READ SORT " + // + "FUNCTION {test}{ title missing$ cite$ } " + // + "ITERATE { test }"); List v = new ArrayList<>(); v.add(t1BibtexEntry()); v.add(TestVM.bibtexString2BibtexEntry("@article{test, author=\"No title\"}")); vm.run(v); - Assert.assertEquals(4, vm.getStack().size()); + assertEquals(4, vm.getStack().size()); - Assert.assertEquals("test", vm.getStack().pop()); - Assert.assertEquals(1, vm.getStack().pop()); - Assert.assertEquals("canh05", vm.getStack().pop()); - Assert.assertEquals(0, vm.getStack().pop()); + assertEquals("test", vm.getStack().pop()); + assertEquals(1, vm.getStack().pop()); + assertEquals("canh05", vm.getStack().pop()); + assertEquals(0, vm.getStack().pop()); } @Test @@ -516,8 +512,8 @@ public void testFormatName() throws RecognitionException { List v = new ArrayList<>(); vm.run(v); - Assert.assertEquals("de~la Vall{\\'e}e~Poussin, C.~L. X.~J?", vm.getStack().pop()); - Assert.assertEquals(0, vm.getStack().size()); + assertEquals("de~la Vall{\\'e}e~Poussin, C.~L. X.~J?", vm.getStack().pop()); + assertEquals(0, vm.getStack().size()); } @Test @@ -531,9 +527,9 @@ public void testFormatName2() throws RecognitionException, IOException { v.add(TestVM.bibtexString2BibtexEntry( "@book{test, author=\"Jonathan Meyer and Charles Louis Xavier Joseph de la Vall{\\'e}e Poussin\"}")); vm.run(v); - Assert.assertEquals("de~la Vall{\\'e}e~Poussin, C.~L. X.~J?", vm.getStack().pop()); - Assert.assertEquals("Annabi, H?", vm.getStack().pop()); - Assert.assertEquals(0, vm.getStack().size()); + assertEquals("de~la Vall{\\'e}e~Poussin, C.~L. X.~J?", vm.getStack().pop()); + assertEquals("Annabi, H?", vm.getStack().pop()); + assertEquals(0, vm.getStack().size()); } @Test @@ -542,21 +538,20 @@ public void testCallType() throws RecognitionException, IOException { VM vm = new VM( "ENTRY { title } { } { label } FUNCTION {presort} { cite$ 'sort.key$ := } ITERATE { presort } READ SORT " + "FUNCTION {inproceedings}{ \"InProceedings called on \" title * } " - + "FUNCTION {book}{ \"Book called on \" title * } " + " ITERATE { call.type$ }" - ); + + "FUNCTION {book}{ \"Book called on \" title * } " + " ITERATE { call.type$ }"); List v = new ArrayList<>(); v.add(t1BibtexEntry()); v.add(TestVM.bibtexString2BibtexEntry("@book{test, title=\"Test\"}")); vm.run(v); - Assert.assertEquals(2, vm.getStack().size()); + assertEquals(2, vm.getStack().size()); - Assert.assertEquals("Book called on Test", vm.getStack().pop()); - Assert.assertEquals( + assertEquals("Book called on Test", vm.getStack().pop()); + assertEquals( "InProceedings called on Effective work practices for floss development: A model and propositions", vm.getStack().pop()); - Assert.assertEquals(0, vm.getStack().size()); + assertEquals(0, vm.getStack().size()); } @Test @@ -572,16 +567,16 @@ public void testIterate() throws RecognitionException, IOException { vm.run(v); - Assert.assertEquals(2, vm.getStack().size()); + assertEquals(2, vm.getStack().size()); String s1 = (String) vm.getStack().pop(); String s2 = (String) vm.getStack().pop(); if ("canh05".equals(s1)) { - Assert.assertEquals("test", s2); + assertEquals("test", s2); } else { - Assert.assertEquals("canh05", s2); - Assert.assertEquals("test", s1); + assertEquals("canh05", s2); + assertEquals("test", s1); } } @@ -626,8 +621,8 @@ public void testWidth() throws RecognitionException, IOException { vm.run(v); - Assert.assertTrue(vm.getIntegers().containsKey("longest.label.width")); - Assert.assertEquals("\\begin{thebibliography}{1}", vm.getStack().pop()); + assertTrue(vm.getIntegers().containsKey("longest.label.width")); + assertEquals("\\begin{thebibliography}{1}", vm.getStack().pop()); } @Test @@ -638,15 +633,15 @@ public void testVMSwap() throws RecognitionException { List v = new ArrayList<>(); vm.run(v); - Assert.assertEquals(2, vm.getStack().size()); - Assert.assertEquals(3, vm.getStack().pop()); - Assert.assertEquals("Hallo", vm.getStack().pop()); + assertEquals(2, vm.getStack().size()); + assertEquals(3, vm.getStack().pop()); + assertEquals("Hallo", vm.getStack().pop()); } private static BibEntry bibtexString2BibtexEntry(String s) throws IOException { ParserResult result = new BibtexParser(mock(ImportFormatPreferences.class, Answers.RETURNS_DEEP_STUBS), new DummyFileUpdateMonitor()).parse(new StringReader(s)); Collection c = result.getDatabase().getEntries(); - Assert.assertEquals(1, c.size()); + assertEquals(1, c.size()); return c.iterator().next(); } @@ -665,7 +660,7 @@ public void testHypthenatedName() throws RecognitionException, IOException { VM vm = new VM(new File("src/test/resources/org/jabref/logic/bst/abbrv.bst")); List v = new ArrayList<>(); v.add(TestVM.bibtexString2BibtexEntry("@article{canh05, author = \"Jean-Paul Sartre\" }")); - Assert.assertTrue(vm.run(v).contains("J.-P. Sartre")); + assertTrue(vm.run(v).contains("J.-P. Sartre")); } private BibEntry t1BibtexEntry() throws IOException { diff --git a/src/test/java/org/jabref/logic/bst/TextPrefixFunctionTest.java b/src/test/java/org/jabref/logic/bst/TextPrefixFunctionTest.java index 9c106207a23..353a7643314 100644 --- a/src/test/java/org/jabref/logic/bst/TextPrefixFunctionTest.java +++ b/src/test/java/org/jabref/logic/bst/TextPrefixFunctionTest.java @@ -1,7 +1,9 @@ package org.jabref.logic.bst; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; public class TextPrefixFunctionTest { @@ -19,8 +21,7 @@ public void testPrefix() { } private static void assertPrefix(final String string, final String string2) { - Assert.assertEquals(string, BibtexTextPrefix.textPrefix(5, string2, s -> - Assert.fail("Should not Warn! text.prefix$ should be " + string + " for (5) " + string2))); + assertEquals(string, BibtexTextPrefix.textPrefix(5, string2, s -> fail("Should not Warn! text.prefix$ should be " + string + " for (5) " + string2))); } } diff --git a/src/test/java/org/jabref/logic/citationstyle/CitationStyleGeneratorTest.java b/src/test/java/org/jabref/logic/citationstyle/CitationStyleGeneratorTest.java index 4819198f596..3a89099e73d 100644 --- a/src/test/java/org/jabref/logic/citationstyle/CitationStyleGeneratorTest.java +++ b/src/test/java/org/jabref/logic/citationstyle/CitationStyleGeneratorTest.java @@ -5,7 +5,7 @@ import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.FieldName; -import org.junit.Test; +import org.junit.jupiter.api.Test; import static org.junit.Assert.assertEquals; diff --git a/src/test/java/org/jabref/logic/citationstyle/CitationStyleTest.java b/src/test/java/org/jabref/logic/citationstyle/CitationStyleTest.java index 79d8f19cf1d..b63d9d94f0e 100644 --- a/src/test/java/org/jabref/logic/citationstyle/CitationStyleTest.java +++ b/src/test/java/org/jabref/logic/citationstyle/CitationStyleTest.java @@ -2,15 +2,16 @@ import org.jabref.logic.util.TestEntry; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; public class CitationStyleTest { @Test public void getDefault() throws Exception { - Assert.assertNotNull(CitationStyle.getDefault()); + assertNotNull(CitationStyle.getDefault()); } @Test @@ -24,7 +25,7 @@ public void testDefaultCitation() { "BibTeX Journal, vol. 34, no. 3, pp. 45–67, Jul. 2016.\n" + " \n"; - Assert.assertEquals(expected, citation); + assertEquals(expected, citation); } } diff --git a/src/test/java/org/jabref/logic/cleanup/ConvertToBiblatexCleanupTest.java b/src/test/java/org/jabref/logic/cleanup/ConvertToBiblatexCleanupTest.java index f6ac76d65ad..104eb31b6ed 100644 --- a/src/test/java/org/jabref/logic/cleanup/ConvertToBiblatexCleanupTest.java +++ b/src/test/java/org/jabref/logic/cleanup/ConvertToBiblatexCleanupTest.java @@ -5,15 +5,16 @@ import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.FieldName; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; public class ConvertToBiblatexCleanupTest { private ConvertToBiblatexCleanup worker; - @Before + @BeforeEach public void setUp() { worker = new ConvertToBiblatexCleanup(); } @@ -26,9 +27,9 @@ public void cleanupMovesYearMonthToDate() { worker.cleanup(entry); - Assert.assertEquals(Optional.empty(), entry.getField(FieldName.YEAR)); - Assert.assertEquals(Optional.empty(), entry.getField(FieldName.MONTH)); - Assert.assertEquals(Optional.of("2011-01"), entry.getField(FieldName.DATE)); + assertEquals(Optional.empty(), entry.getField(FieldName.YEAR)); + assertEquals(Optional.empty(), entry.getField(FieldName.MONTH)); + assertEquals(Optional.of("2011-01"), entry.getField(FieldName.DATE)); } @Test @@ -40,9 +41,9 @@ public void cleanupWithDateAlreadyPresentDoesNothing() { worker.cleanup(entry); - Assert.assertEquals(Optional.of("2011"), entry.getField(FieldName.YEAR)); - Assert.assertEquals(Optional.of("#jan#"), entry.getField(FieldName.MONTH)); - Assert.assertEquals(Optional.of("2012"), entry.getField(FieldName.DATE)); + assertEquals(Optional.of("2011"), entry.getField(FieldName.YEAR)); + assertEquals(Optional.of("#jan#"), entry.getField(FieldName.MONTH)); + assertEquals(Optional.of("2012"), entry.getField(FieldName.DATE)); } @Test @@ -51,7 +52,7 @@ public void cleanupMovesJournalToJournaltitle() { worker.cleanup(entry); - Assert.assertEquals(Optional.empty(), entry.getField(FieldName.JOURNAL)); - Assert.assertEquals(Optional.of("Best of JabRef"), entry.getField(FieldName.JOURNALTITLE)); + assertEquals(Optional.empty(), entry.getField(FieldName.JOURNAL)); + assertEquals(Optional.of("Best of JabRef"), entry.getField(FieldName.JOURNALTITLE)); } } diff --git a/src/test/java/org/jabref/logic/cleanup/ConvertToBibtexCleanupTest.java b/src/test/java/org/jabref/logic/cleanup/ConvertToBibtexCleanupTest.java index 5b5de9d37b4..df46c7da884 100644 --- a/src/test/java/org/jabref/logic/cleanup/ConvertToBibtexCleanupTest.java +++ b/src/test/java/org/jabref/logic/cleanup/ConvertToBibtexCleanupTest.java @@ -5,15 +5,16 @@ import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.FieldName; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; public class ConvertToBibtexCleanupTest { private ConvertToBibtexCleanup worker; - @Before + @BeforeEach public void setUp() { worker = new ConvertToBibtexCleanup(); } @@ -24,9 +25,9 @@ public void cleanupMovesDateToYearAndMonth() { worker.cleanup(entry); - Assert.assertEquals(Optional.empty(), entry.getField(FieldName.DATE)); - Assert.assertEquals(Optional.of("2011"), entry.getField(FieldName.YEAR)); - Assert.assertEquals(Optional.of("#jan#"), entry.getField(FieldName.MONTH)); + assertEquals(Optional.empty(), entry.getField(FieldName.DATE)); + assertEquals(Optional.of("2011"), entry.getField(FieldName.YEAR)); + assertEquals(Optional.of("#jan#"), entry.getField(FieldName.MONTH)); } @Test @@ -37,8 +38,8 @@ public void cleanupWithYearAlreadyPresentDoesNothing() { worker.cleanup(entry); - Assert.assertEquals(Optional.of("2011"), entry.getField(FieldName.YEAR)); - Assert.assertEquals(Optional.of("2012"), entry.getField(FieldName.DATE)); + assertEquals(Optional.of("2011"), entry.getField(FieldName.YEAR)); + assertEquals(Optional.of("2012"), entry.getField(FieldName.DATE)); } @Test @@ -47,7 +48,7 @@ public void cleanupMovesJournaltitleToJournal() { worker.cleanup(entry); - Assert.assertEquals(Optional.empty(), entry.getField(FieldName.JOURNALTITLE)); - Assert.assertEquals(Optional.of("Best of JabRef"), entry.getField(FieldName.JOURNAL)); + assertEquals(Optional.empty(), entry.getField(FieldName.JOURNALTITLE)); + assertEquals(Optional.of("Best of JabRef"), entry.getField(FieldName.JOURNAL)); } } diff --git a/src/test/java/org/jabref/logic/cleanup/FieldFormatterCleanupTest.java b/src/test/java/org/jabref/logic/cleanup/FieldFormatterCleanupTest.java index e7b01d90b1e..37833d0c2bc 100644 --- a/src/test/java/org/jabref/logic/cleanup/FieldFormatterCleanupTest.java +++ b/src/test/java/org/jabref/logic/cleanup/FieldFormatterCleanupTest.java @@ -10,16 +10,17 @@ import org.jabref.model.entry.BibtexEntryTypes; import org.jabref.model.entry.FieldName; -import org.junit.Assert; -import org.junit.Before; import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; + +import static org.junit.jupiter.api.Assertions.assertEquals; public class FieldFormatterCleanupTest { private BibEntry entry; private Map fieldMap; - @Before + @BeforeEach public void setUp() { fieldMap = new HashMap<>(); entry = new BibEntry(); @@ -41,13 +42,13 @@ public void testInternalAllField() throws Exception { FieldFormatterCleanup cleanup = new FieldFormatterCleanup(FieldName.INTERNAL_ALL_FIELD, new UpperCaseFormatter()); cleanup.cleanup(entry); - Assert.assertEquals(fieldMap.get("title").toUpperCase(), entry.getField("title").get()); - Assert.assertEquals(fieldMap.get("booktitle").toUpperCase(), entry.getField("booktitle").get()); - Assert.assertEquals(fieldMap.get("year").toUpperCase(), entry.getField("year").get()); - Assert.assertEquals(fieldMap.get("month").toUpperCase(), entry.getField("month").get()); - Assert.assertEquals(fieldMap.get("abstract").toUpperCase(), entry.getField("abstract").get()); - Assert.assertEquals(fieldMap.get("doi").toUpperCase(), entry.getField("doi").get()); - Assert.assertEquals(fieldMap.get("issn").toUpperCase(), entry.getField("issn").get()); + assertEquals(fieldMap.get("title").toUpperCase(), entry.getField("title").get()); + assertEquals(fieldMap.get("booktitle").toUpperCase(), entry.getField("booktitle").get()); + assertEquals(fieldMap.get("year").toUpperCase(), entry.getField("year").get()); + assertEquals(fieldMap.get("month").toUpperCase(), entry.getField("month").get()); + assertEquals(fieldMap.get("abstract").toUpperCase(), entry.getField("abstract").get()); + assertEquals(fieldMap.get("doi").toUpperCase(), entry.getField("doi").get()); + assertEquals(fieldMap.get("issn").toUpperCase(), entry.getField("issn").get()); } @Test @@ -55,12 +56,12 @@ public void testInternalAllTextFieldsField() throws Exception { FieldFormatterCleanup cleanup = new FieldFormatterCleanup(FieldName.INTERNAL_ALL_TEXT_FIELDS_FIELD, new UpperCaseFormatter()); cleanup.cleanup(entry); - Assert.assertEquals(fieldMap.get("title").toUpperCase(), entry.getField("title").get()); - Assert.assertEquals(fieldMap.get("booktitle").toUpperCase(), entry.getField("booktitle").get()); - Assert.assertEquals(fieldMap.get("year"), entry.getField("year").get()); - Assert.assertEquals(fieldMap.get("month"), entry.getField("month").get()); - Assert.assertEquals(fieldMap.get("abstract").toUpperCase(), entry.getField("abstract").get()); - Assert.assertEquals(fieldMap.get("doi"), entry.getField("doi").get()); - Assert.assertEquals(fieldMap.get("issn"), entry.getField("issn").get()); + assertEquals(fieldMap.get("title").toUpperCase(), entry.getField("title").get()); + assertEquals(fieldMap.get("booktitle").toUpperCase(), entry.getField("booktitle").get()); + assertEquals(fieldMap.get("year"), entry.getField("year").get()); + assertEquals(fieldMap.get("month"), entry.getField("month").get()); + assertEquals(fieldMap.get("abstract").toUpperCase(), entry.getField("abstract").get()); + assertEquals(fieldMap.get("doi"), entry.getField("doi").get()); + assertEquals(fieldMap.get("issn"), entry.getField("issn").get()); } } diff --git a/src/test/java/org/jabref/logic/cleanup/ISSNCleanupTest.java b/src/test/java/org/jabref/logic/cleanup/ISSNCleanupTest.java index 3dd3f5f4d02..c4827f7eef0 100644 --- a/src/test/java/org/jabref/logic/cleanup/ISSNCleanupTest.java +++ b/src/test/java/org/jabref/logic/cleanup/ISSNCleanupTest.java @@ -7,18 +7,17 @@ import org.jabref.model.entry.BibEntry; import org.jabref.model.metadata.FileDirectoryPreferences; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.mock; public class ISSNCleanupTest { private CleanupWorker worker; - - @Before + @BeforeEach public void setUp() { worker = new CleanupWorker(mock(BibDatabaseContext.class), new CleanupPreferences("", "", mock(LayoutFormatterPreferences.class), @@ -32,7 +31,7 @@ public void cleanupISSNReturnsCorrectISSN() { entry.setField("issn", "0123-4567"); worker.cleanup(preset, entry); - Assert.assertEquals(Optional.of("0123-4567"), entry.getField("issn")); + assertEquals(Optional.of("0123-4567"), entry.getField("issn")); } @Test @@ -42,7 +41,7 @@ public void cleanupISSNAddsMissingDash() { entry.setField("issn", "01234567"); worker.cleanup(preset, entry); - Assert.assertEquals(Optional.of("0123-4567"), entry.getField("issn")); + assertEquals(Optional.of("0123-4567"), entry.getField("issn")); } @Test @@ -52,7 +51,7 @@ public void cleanupISSNJunkStaysJunk() { entry.setField("issn", "Banana"); worker.cleanup(preset, entry); - Assert.assertEquals(Optional.of("Banana"), entry.getField("issn")); + assertEquals(Optional.of("Banana"), entry.getField("issn")); } } diff --git a/src/test/java/org/jabref/logic/exporter/BibtexDatabaseWriterTest.java b/src/test/java/org/jabref/logic/exporter/BibtexDatabaseWriterTest.java index b0225863f31..bba2ec0e65a 100644 --- a/src/test/java/org/jabref/logic/exporter/BibtexDatabaseWriterTest.java +++ b/src/test/java/org/jabref/logic/exporter/BibtexDatabaseWriterTest.java @@ -38,11 +38,12 @@ import org.jabref.model.util.DummyFileUpdateMonitor; import org.jabref.model.util.FileUpdateMonitor; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.mockito.Answers; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.Mockito.mock; public class BibtexDatabaseWriterTest { @@ -52,9 +53,9 @@ public class BibtexDatabaseWriterTest { private MetaData metaData; private BibDatabaseContext bibtexContext; private ImportFormatPreferences importFormatPreferences; - private FileUpdateMonitor fileMonitor = new DummyFileUpdateMonitor(); + private final FileUpdateMonitor fileMonitor = new DummyFileUpdateMonitor(); - @Before + @BeforeEach public void setUp() { // Write to a string instead of to a file databaseWriter = new BibtexDatabaseWriter<>(StringSaveSession::new); @@ -65,19 +66,17 @@ public void setUp() { importFormatPreferences = mock(ImportFormatPreferences.class, Answers.RETURNS_DEEP_STUBS); } - @Test(expected = NullPointerException.class) + @Test public void writeWithNullContextThrowsException() throws Exception { - databaseWriter.savePartOfDatabase(null, Collections.emptyList(), new SavePreferences()); + assertThrows(NullPointerException.class, () -> databaseWriter.savePartOfDatabase(null, Collections.emptyList(), new SavePreferences())); } - @Test(expected = NullPointerException.class) public void writeWithNullEntriesThrowsException() throws Exception { - databaseWriter.savePartOfDatabase(bibtexContext, null, new SavePreferences()); + assertThrows(NullPointerException.class, () -> databaseWriter.savePartOfDatabase(bibtexContext, null, new SavePreferences())); } - @Test(expected = NullPointerException.class) public void writeWithNullPreferencesThrowsException() throws Exception { - databaseWriter.savePartOfDatabase(bibtexContext, Collections.emptyList(), null); + assertThrows(NullPointerException.class, () -> databaseWriter.savePartOfDatabase(bibtexContext, Collections.emptyList(), null)); } @Test diff --git a/src/test/java/org/jabref/logic/exporter/FieldFormatterCleanupsTest.java b/src/test/java/org/jabref/logic/exporter/FieldFormatterCleanupsTest.java index e8b2bf37613..3958a1c5892 100644 --- a/src/test/java/org/jabref/logic/exporter/FieldFormatterCleanupsTest.java +++ b/src/test/java/org/jabref/logic/exporter/FieldFormatterCleanupsTest.java @@ -15,8 +15,8 @@ import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.BibtexEntryTypes; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import static org.junit.Assert.assertEquals; @@ -25,7 +25,7 @@ public class FieldFormatterCleanupsTest { private BibEntry entry; - @Before + @BeforeEach public void setUp() { entry = new BibEntry(); entry.setType(BibtexEntryTypes.INPROCEEDINGS); diff --git a/src/test/java/org/jabref/logic/exporter/GroupSerializerTest.java b/src/test/java/org/jabref/logic/exporter/GroupSerializerTest.java index 4c587bf0dcb..380515100de 100644 --- a/src/test/java/org/jabref/logic/exporter/GroupSerializerTest.java +++ b/src/test/java/org/jabref/logic/exporter/GroupSerializerTest.java @@ -24,8 +24,8 @@ import org.jabref.model.groups.WordKeywordGroup; import org.jabref.model.util.DummyFileUpdateMonitor; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import static org.junit.Assert.assertEquals; @@ -33,7 +33,7 @@ public class GroupSerializerTest { private GroupSerializer groupSerializer; - @Before + @BeforeEach public void setUp() throws Exception { groupSerializer = new GroupSerializer(); } diff --git a/src/test/java/org/jabref/logic/exporter/MetaDataSerializerTest.java b/src/test/java/org/jabref/logic/exporter/MetaDataSerializerTest.java index 92c94d57c6a..8a9918a0295 100644 --- a/src/test/java/org/jabref/logic/exporter/MetaDataSerializerTest.java +++ b/src/test/java/org/jabref/logic/exporter/MetaDataSerializerTest.java @@ -14,8 +14,8 @@ import org.jabref.model.metadata.ContentSelector; import org.jabref.model.metadata.MetaData; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import static org.junit.Assert.assertEquals; @@ -24,7 +24,7 @@ public class MetaDataSerializerTest { private MetaData metaData; private GlobalBibtexKeyPattern pattern; - @Before + @BeforeEach public void setUp() { metaData = new MetaData(); pattern = GlobalBibtexKeyPattern.fromPattern("[auth][year]"); diff --git a/src/test/java/org/jabref/logic/formatter/IdentityFormatterTest.java b/src/test/java/org/jabref/logic/formatter/IdentityFormatterTest.java index 8cdf12fafab..8fb9eadf959 100644 --- a/src/test/java/org/jabref/logic/formatter/IdentityFormatterTest.java +++ b/src/test/java/org/jabref/logic/formatter/IdentityFormatterTest.java @@ -1,9 +1,9 @@ package org.jabref.logic.formatter; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; /** * Tests in addition to the general tests from {@link org.jabref.logic.formatter.FormatterTest} @@ -12,7 +12,7 @@ public class IdentityFormatterTest { private IdentityFormatter formatter; - @Before + @BeforeEach public void setUp() { formatter = new IdentityFormatter(); } diff --git a/src/test/java/org/jabref/logic/formatter/bibtexfields/ClearFormatterTest.java b/src/test/java/org/jabref/logic/formatter/bibtexfields/ClearFormatterTest.java index f93a2f2dda7..3c2fe1b9f67 100644 --- a/src/test/java/org/jabref/logic/formatter/bibtexfields/ClearFormatterTest.java +++ b/src/test/java/org/jabref/logic/formatter/bibtexfields/ClearFormatterTest.java @@ -1,19 +1,20 @@ package org.jabref.logic.formatter.bibtexfields; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + /** * Tests in addition to the general tests from {@link org.jabref.logic.formatter.FormatterTest} */ -import org.junit.Before; -import org.junit.Test; - -import static org.junit.Assert.assertEquals; public class ClearFormatterTest { private ClearFormatter formatter; - @Before + @BeforeEach public void setUp() { formatter = new ClearFormatter(); } diff --git a/src/test/java/org/jabref/logic/formatter/bibtexfields/EscapeUnderscoresFormatterTest.java b/src/test/java/org/jabref/logic/formatter/bibtexfields/EscapeUnderscoresFormatterTest.java index 9b5ecd7bcd4..bfd2312ff87 100644 --- a/src/test/java/org/jabref/logic/formatter/bibtexfields/EscapeUnderscoresFormatterTest.java +++ b/src/test/java/org/jabref/logic/formatter/bibtexfields/EscapeUnderscoresFormatterTest.java @@ -1,16 +1,15 @@ package org.jabref.logic.formatter.bibtexfields; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class EscapeUnderscoresFormatterTest { - private EscapeUnderscoresFormatter formatter; - @Before + @BeforeEach public void setUp() { formatter = new EscapeUnderscoresFormatter(); } diff --git a/src/test/java/org/jabref/logic/formatter/bibtexfields/HtmlToLatexFormatterTest.java b/src/test/java/org/jabref/logic/formatter/bibtexfields/HtmlToLatexFormatterTest.java index ee1889e03b8..b8b6ac22ec3 100644 --- a/src/test/java/org/jabref/logic/formatter/bibtexfields/HtmlToLatexFormatterTest.java +++ b/src/test/java/org/jabref/logic/formatter/bibtexfields/HtmlToLatexFormatterTest.java @@ -1,9 +1,9 @@ package org.jabref.logic.formatter.bibtexfields; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; /** * Tests in addition to the general tests from {@link org.jabref.logic.formatter.FormatterTest} @@ -12,7 +12,7 @@ public class HtmlToLatexFormatterTest { private HtmlToLatexFormatter formatter; - @Before + @BeforeEach public void setUp() { formatter = new HtmlToLatexFormatter(); } diff --git a/src/test/java/org/jabref/logic/formatter/bibtexfields/HtmlToUnicodeFormatterTest.java b/src/test/java/org/jabref/logic/formatter/bibtexfields/HtmlToUnicodeFormatterTest.java index 524cac445c8..13ce11e3d05 100644 --- a/src/test/java/org/jabref/logic/formatter/bibtexfields/HtmlToUnicodeFormatterTest.java +++ b/src/test/java/org/jabref/logic/formatter/bibtexfields/HtmlToUnicodeFormatterTest.java @@ -1,15 +1,15 @@ package org.jabref.logic.formatter.bibtexfields; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class HtmlToUnicodeFormatterTest { private HtmlToUnicodeFormatter formatter; - @Before + @BeforeEach public void setUp() { formatter = new HtmlToUnicodeFormatter(); } diff --git a/src/test/java/org/jabref/logic/formatter/bibtexfields/LatexCleanupFormatterTest.java b/src/test/java/org/jabref/logic/formatter/bibtexfields/LatexCleanupFormatterTest.java index f2821ff4431..4e24f6ccaa2 100644 --- a/src/test/java/org/jabref/logic/formatter/bibtexfields/LatexCleanupFormatterTest.java +++ b/src/test/java/org/jabref/logic/formatter/bibtexfields/LatexCleanupFormatterTest.java @@ -1,9 +1,9 @@ package org.jabref.logic.formatter.bibtexfields; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; /** * Tests in addition to the general tests from {@link org.jabref.logic.formatter.FormatterTest} @@ -12,7 +12,7 @@ public class LatexCleanupFormatterTest { private LatexCleanupFormatter formatter; - @Before + @BeforeEach public void setUp() { formatter = new LatexCleanupFormatter(); } diff --git a/src/test/java/org/jabref/logic/formatter/bibtexfields/NormalizeDateFormatterTest.java b/src/test/java/org/jabref/logic/formatter/bibtexfields/NormalizeDateFormatterTest.java index 0f432d0408e..92ddc83ebf3 100644 --- a/src/test/java/org/jabref/logic/formatter/bibtexfields/NormalizeDateFormatterTest.java +++ b/src/test/java/org/jabref/logic/formatter/bibtexfields/NormalizeDateFormatterTest.java @@ -1,8 +1,9 @@ package org.jabref.logic.formatter.bibtexfields; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; /** * Tests in addition to the general tests from {@link org.jabref.logic.formatter.FormatterTest} @@ -11,128 +12,128 @@ public class NormalizeDateFormatterTest { private NormalizeDateFormatter formatter; - @Before + @BeforeEach public void setUp() { formatter = new NormalizeDateFormatter(); } @Test public void formatDateYYYYMM0D() { - Assert.assertEquals("2015-11-08", formatter.format("2015-11-08")); + assertEquals("2015-11-08", formatter.format("2015-11-08")); } @Test public void formatDateYYYYM0D() { - Assert.assertEquals("2015-01-08", formatter.format("2015-1-08")); + assertEquals("2015-01-08", formatter.format("2015-1-08")); } @Test public void formatDateYYYYMD() { - Assert.assertEquals("2015-01-08", formatter.format("2015-1-8")); + assertEquals("2015-01-08", formatter.format("2015-1-8")); } @Test public void formatDateYYYYMM() { - Assert.assertEquals("2015-11", formatter.format("2015-11")); + assertEquals("2015-11", formatter.format("2015-11")); } @Test public void formatDateYYYYM() { - Assert.assertEquals("2015-01", formatter.format("2015-1")); + assertEquals("2015-01", formatter.format("2015-1")); } @Test public void formatDateMMYY() { - Assert.assertEquals("2015-11", formatter.format("11/15")); + assertEquals("2015-11", formatter.format("11/15")); } @Test public void formatDateMYY() { - Assert.assertEquals("2015-01", formatter.format("1/15")); + assertEquals("2015-01", formatter.format("1/15")); } @Test public void formatDate0MYY() { - Assert.assertEquals("2015-01", formatter.format("01/15")); + assertEquals("2015-01", formatter.format("01/15")); } @Test public void formatDateMMYYYY() { - Assert.assertEquals("2015-11", formatter.format("11/2015")); + assertEquals("2015-11", formatter.format("11/2015")); } @Test public void formatDateMYYYY() { - Assert.assertEquals("2015-01", formatter.format("1/2015")); + assertEquals("2015-01", formatter.format("1/2015")); } @Test public void formatDate0MYYYY() { - Assert.assertEquals("2015-01", formatter.format("01/2015")); + assertEquals("2015-01", formatter.format("01/2015")); } @Test public void formatDateMMMDDCommaYYYY() { - Assert.assertEquals("2015-11-08", formatter.format("November 08, 2015")); + assertEquals("2015-11-08", formatter.format("November 08, 2015")); } @Test public void formatDateMMMDCommaYYYY() { - Assert.assertEquals("2015-11-08", formatter.format("November 8, 2015")); + assertEquals("2015-11-08", formatter.format("November 8, 2015")); } @Test public void formatDateMMMCommaYYYY() { - Assert.assertEquals("2015-11", formatter.format("November, 2015")); + assertEquals("2015-11", formatter.format("November, 2015")); } @Test public void formatDate0DdotMMdotYYYY() { - Assert.assertEquals("2015-11-08", formatter.format("08.11.2015")); + assertEquals("2015-11-08", formatter.format("08.11.2015")); } @Test public void formatDateDdotMMdotYYYY() { - Assert.assertEquals("2015-11-08", formatter.format("8.11.2015")); + assertEquals("2015-11-08", formatter.format("8.11.2015")); } @Test public void formatDateDDdotMMdotYYYY() { - Assert.assertEquals("2015-11-15", formatter.format("15.11.2015")); + assertEquals("2015-11-15", formatter.format("15.11.2015")); } @Test public void formatDate0Ddot0MdotYYYY() { - Assert.assertEquals("2015-01-08", formatter.format("08.01.2015")); + assertEquals("2015-01-08", formatter.format("08.01.2015")); } @Test public void formatDateDdot0MdotYYYY() { - Assert.assertEquals("2015-01-08", formatter.format("8.01.2015")); + assertEquals("2015-01-08", formatter.format("8.01.2015")); } @Test public void formatDateDDdot0MdotYYYY() { - Assert.assertEquals("2015-01-15", formatter.format("15.01.2015")); + assertEquals("2015-01-15", formatter.format("15.01.2015")); } @Test public void formatDate0DdotMdotYYYY() { - Assert.assertEquals("2015-01-08", formatter.format("08.1.2015")); + assertEquals("2015-01-08", formatter.format("08.1.2015")); } @Test public void formatDateDdotMdotYYYY() { - Assert.assertEquals("2015-01-08", formatter.format("8.1.2015")); + assertEquals("2015-01-08", formatter.format("8.1.2015")); } @Test public void formatDateDDdotMdotYYYY() { - Assert.assertEquals("2015-01-15", formatter.format("15.1.2015")); + assertEquals("2015-01-15", formatter.format("15.1.2015")); } @Test public void formatExample() { - Assert.assertEquals("2003-11-29", formatter.format(formatter.getExampleInput())); + assertEquals("2003-11-29", formatter.format(formatter.getExampleInput())); } } diff --git a/src/test/java/org/jabref/logic/formatter/bibtexfields/NormalizeMonthFormatterTest.java b/src/test/java/org/jabref/logic/formatter/bibtexfields/NormalizeMonthFormatterTest.java index 437aefa059a..c6253e15112 100644 --- a/src/test/java/org/jabref/logic/formatter/bibtexfields/NormalizeMonthFormatterTest.java +++ b/src/test/java/org/jabref/logic/formatter/bibtexfields/NormalizeMonthFormatterTest.java @@ -1,8 +1,9 @@ package org.jabref.logic.formatter.bibtexfields; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; /** * Tests in addition to the general tests from {@link org.jabref.logic.formatter.FormatterTest} @@ -11,14 +12,14 @@ public class NormalizeMonthFormatterTest { private NormalizeMonthFormatter formatter; - @Before + @BeforeEach public void setUp() { formatter = new NormalizeMonthFormatter(); } @Test public void formatExample() { - Assert.assertEquals("#dec#", formatter.format(formatter.getExampleInput())); + assertEquals("#dec#", formatter.format(formatter.getExampleInput())); } } diff --git a/src/test/java/org/jabref/logic/formatter/bibtexfields/NormalizeNamesFormatterTest.java b/src/test/java/org/jabref/logic/formatter/bibtexfields/NormalizeNamesFormatterTest.java index 05498b0b9d8..c2f74c4d560 100644 --- a/src/test/java/org/jabref/logic/formatter/bibtexfields/NormalizeNamesFormatterTest.java +++ b/src/test/java/org/jabref/logic/formatter/bibtexfields/NormalizeNamesFormatterTest.java @@ -1,9 +1,9 @@ package org.jabref.logic.formatter.bibtexfields; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; /** * Tests in addition to the general tests from {@link org.jabref.logic.formatter.FormatterTest} @@ -12,7 +12,7 @@ public class NormalizeNamesFormatterTest { private NormalizeNamesFormatter formatter; - @Before + @BeforeEach public void setUp() { formatter = new NormalizeNamesFormatter(); } diff --git a/src/test/java/org/jabref/logic/formatter/bibtexfields/NormalizePagesFormatterTest.java b/src/test/java/org/jabref/logic/formatter/bibtexfields/NormalizePagesFormatterTest.java index 0aeadd11251..77468ca156f 100644 --- a/src/test/java/org/jabref/logic/formatter/bibtexfields/NormalizePagesFormatterTest.java +++ b/src/test/java/org/jabref/logic/formatter/bibtexfields/NormalizePagesFormatterTest.java @@ -1,8 +1,9 @@ package org.jabref.logic.formatter.bibtexfields; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; /** * Tests in addition to the general tests from {@link org.jabref.logic.formatter.FormatterTest} @@ -11,101 +12,101 @@ public class NormalizePagesFormatterTest { private NormalizePagesFormatter formatter; - @Before + @BeforeEach public void setUp() { formatter = new NormalizePagesFormatter(); } @Test public void formatSinglePageResultsInNoChange() { - Assert.assertEquals("1", formatter.format("1")); + assertEquals("1", formatter.format("1")); } @Test public void formatPageNumbers() { - Assert.assertEquals("1--2", formatter.format("1-2")); + assertEquals("1--2", formatter.format("1-2")); } @Test public void formatPageNumbersCommaSeparated() { - Assert.assertEquals("1,2,3", formatter.format("1,2,3")); + assertEquals("1,2,3", formatter.format("1,2,3")); } @Test public void formatPageNumbersPlusRange() { - Assert.assertEquals("43+", formatter.format("43+")); + assertEquals("43+", formatter.format("43+")); } @Test public void ignoreWhitespaceInPageNumbers() { - Assert.assertEquals("1--2", formatter.format(" 1 - 2 ")); + assertEquals("1--2", formatter.format(" 1 - 2 ")); } @Test public void removeWhitespaceSinglePage() { - Assert.assertEquals("1", formatter.format(" 1 ")); + assertEquals("1", formatter.format(" 1 ")); } @Test public void removeWhitespacePageRange() { - Assert.assertEquals("1--2", formatter.format(" 1 -- 2 ")); + assertEquals("1--2", formatter.format(" 1 -- 2 ")); } @Test public void ignoreWhitespaceInPageNumbersWithDoubleDash() { - Assert.assertEquals("43--103", formatter.format("43 -- 103")); + assertEquals("43--103", formatter.format("43 -- 103")); } @Test public void keepCorrectlyFormattedPageNumbers() { - Assert.assertEquals("1--2", formatter.format("1--2")); + assertEquals("1--2", formatter.format("1--2")); } @Test public void formatPageNumbersRemoveUnexpectedLiterals() { - Assert.assertEquals("1--2", formatter.format("{1}-{2}")); + assertEquals("1--2", formatter.format("{1}-{2}")); } @Test public void formatPageNumbersRegexNotMatching() { - Assert.assertEquals("12", formatter.format("12")); + assertEquals("12", formatter.format("12")); } @Test public void doNotRemoveLetters() { - Assert.assertEquals("R1-R50", formatter.format("R1-R50")); + assertEquals("R1-R50", formatter.format("R1-R50")); } @Test public void replaceLongDashWithDoubleDash() { - Assert.assertEquals("1--50", formatter.format("1 \u2014 50")); + assertEquals("1--50", formatter.format("1 \u2014 50")); } @Test public void removePagePrefix() { - Assert.assertEquals("50", formatter.format("p.50")); + assertEquals("50", formatter.format("p.50")); } @Test public void removePagesPrefix() { - Assert.assertEquals("50", formatter.format("pp.50")); + assertEquals("50", formatter.format("pp.50")); } @Test public void formatACMPages() { // This appears in https://doi.org/10.1145/1658373.1658375 - Assert.assertEquals("2:1--2:33", formatter.format("2:1-2:33")); + assertEquals("2:1--2:33", formatter.format("2:1-2:33")); } @Test public void keepFormattedACMPages() { // This appears in https://doi.org/10.1145/1658373.1658375 - Assert.assertEquals("2:1--2:33", formatter.format("2:1--2:33")); + assertEquals("2:1--2:33", formatter.format("2:1--2:33")); } @Test public void formatExample() { - Assert.assertEquals("1--2", formatter.format(formatter.getExampleInput())); + assertEquals("1--2", formatter.format(formatter.getExampleInput())); } } diff --git a/src/test/java/org/jabref/logic/formatter/bibtexfields/OrdinalsToSuperscriptFormatterTest.java b/src/test/java/org/jabref/logic/formatter/bibtexfields/OrdinalsToSuperscriptFormatterTest.java index 134dfa6885c..6fffcf6ee30 100644 --- a/src/test/java/org/jabref/logic/formatter/bibtexfields/OrdinalsToSuperscriptFormatterTest.java +++ b/src/test/java/org/jabref/logic/formatter/bibtexfields/OrdinalsToSuperscriptFormatterTest.java @@ -1,9 +1,9 @@ package org.jabref.logic.formatter.bibtexfields; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; /** * Tests in addition to the general tests from {@link org.jabref.logic.formatter.FormatterTest} @@ -12,7 +12,7 @@ public class OrdinalsToSuperscriptFormatterTest { private OrdinalsToSuperscriptFormatter formatter; - @Before + @BeforeEach public void setUp() { formatter = new OrdinalsToSuperscriptFormatter(); } diff --git a/src/test/java/org/jabref/logic/formatter/bibtexfields/RemoveBracesFormatterTest.java b/src/test/java/org/jabref/logic/formatter/bibtexfields/RemoveBracesFormatterTest.java index d5f6b68234e..7ffb7179bd5 100644 --- a/src/test/java/org/jabref/logic/formatter/bibtexfields/RemoveBracesFormatterTest.java +++ b/src/test/java/org/jabref/logic/formatter/bibtexfields/RemoveBracesFormatterTest.java @@ -1,10 +1,9 @@ package org.jabref.logic.formatter.bibtexfields; -import org.junit.Before; -import org.junit.Test; - -import static org.junit.Assert.assertEquals; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; /** * Tests in addition to the general tests from {@link org.jabref.logic.formatter.FormatterTest} @@ -13,7 +12,7 @@ public class RemoveBracesFormatterTest { private RemoveBracesFormatter formatter; - @Before + @BeforeEach public void setUp() { formatter = new RemoveBracesFormatter(); } diff --git a/src/test/java/org/jabref/logic/formatter/bibtexfields/RemoveHyphenatedNewlinesFormatterTest.java b/src/test/java/org/jabref/logic/formatter/bibtexfields/RemoveHyphenatedNewlinesFormatterTest.java index e34551ae971..207dc06b38b 100644 --- a/src/test/java/org/jabref/logic/formatter/bibtexfields/RemoveHyphenatedNewlinesFormatterTest.java +++ b/src/test/java/org/jabref/logic/formatter/bibtexfields/RemoveHyphenatedNewlinesFormatterTest.java @@ -1,14 +1,14 @@ package org.jabref.logic.formatter.bibtexfields; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class RemoveHyphenatedNewlinesFormatterTest { private RemoveHyphenatedNewlinesFormatter formatter; - @Before + @BeforeEach public void setUp() { formatter = new RemoveHyphenatedNewlinesFormatter(); } diff --git a/src/test/java/org/jabref/logic/formatter/bibtexfields/RemoveNewlinesFormatterTest.java b/src/test/java/org/jabref/logic/formatter/bibtexfields/RemoveNewlinesFormatterTest.java index bc7cfa8210e..96de03b1456 100644 --- a/src/test/java/org/jabref/logic/formatter/bibtexfields/RemoveNewlinesFormatterTest.java +++ b/src/test/java/org/jabref/logic/formatter/bibtexfields/RemoveNewlinesFormatterTest.java @@ -1,14 +1,16 @@ + package org.jabref.logic.formatter.bibtexfields; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class RemoveNewlinesFormatterTest { + private RemoveNewlinesFormatter formatter; - @Before + @BeforeEach public void setUp() { formatter = new RemoveNewlinesFormatter(); } diff --git a/src/test/java/org/jabref/logic/formatter/bibtexfields/UnicodeConverterTest.java b/src/test/java/org/jabref/logic/formatter/bibtexfields/UnicodeConverterTest.java index 0c4c61facf1..fe4d723ad06 100644 --- a/src/test/java/org/jabref/logic/formatter/bibtexfields/UnicodeConverterTest.java +++ b/src/test/java/org/jabref/logic/formatter/bibtexfields/UnicodeConverterTest.java @@ -1,10 +1,9 @@ package org.jabref.logic.formatter.bibtexfields; -import org.junit.Before; -import org.junit.Test; - -import static org.junit.Assert.assertEquals; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; /** * Tests in addition to the general tests from {@link org.jabref.logic.formatter.FormatterTest} @@ -13,7 +12,7 @@ public class UnicodeConverterTest { private UnicodeToLatexFormatter formatter; - @Before + @BeforeEach public void setUp() { formatter = new UnicodeToLatexFormatter(); } diff --git a/src/test/java/org/jabref/logic/formatter/bibtexfields/UnicodeToLatexFormatterTest.java b/src/test/java/org/jabref/logic/formatter/bibtexfields/UnicodeToLatexFormatterTest.java index e065361128f..f4e279158d3 100644 --- a/src/test/java/org/jabref/logic/formatter/bibtexfields/UnicodeToLatexFormatterTest.java +++ b/src/test/java/org/jabref/logic/formatter/bibtexfields/UnicodeToLatexFormatterTest.java @@ -1,9 +1,9 @@ package org.jabref.logic.formatter.bibtexfields; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; /** * Tests in addition to the general tests from {@link org.jabref.logic.formatter.FormatterTest} @@ -12,7 +12,7 @@ public class UnicodeToLatexFormatterTest { private UnicodeToLatexFormatter formatter; - @Before + @BeforeEach public void setUp() { formatter = new UnicodeToLatexFormatter(); } diff --git a/src/test/java/org/jabref/logic/formatter/bibtexfields/UnitsToLatexFormatterTest.java b/src/test/java/org/jabref/logic/formatter/bibtexfields/UnitsToLatexFormatterTest.java index 07dfb2c5485..43d1338831a 100644 --- a/src/test/java/org/jabref/logic/formatter/bibtexfields/UnitsToLatexFormatterTest.java +++ b/src/test/java/org/jabref/logic/formatter/bibtexfields/UnitsToLatexFormatterTest.java @@ -1,10 +1,9 @@ package org.jabref.logic.formatter.bibtexfields; -import org.junit.Before; -import org.junit.Test; - -import static org.junit.Assert.assertEquals; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; /** * Tests in addition to the general tests from {@link org.jabref.logic.formatter.FormatterTest} @@ -13,7 +12,7 @@ public class UnitsToLatexFormatterTest { private UnitsToLatexFormatter formatter; - @Before + @BeforeEach public void setUp() { formatter = new UnitsToLatexFormatter(); } diff --git a/src/test/java/org/jabref/logic/formatter/casechanger/CapitalizeFormatterTest.java b/src/test/java/org/jabref/logic/formatter/casechanger/CapitalizeFormatterTest.java index 04129f6259b..437f42b096a 100644 --- a/src/test/java/org/jabref/logic/formatter/casechanger/CapitalizeFormatterTest.java +++ b/src/test/java/org/jabref/logic/formatter/casechanger/CapitalizeFormatterTest.java @@ -1,8 +1,9 @@ package org.jabref.logic.formatter.casechanger; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; /** * Tests in addition to the general tests from {@link org.jabref.logic.formatter.FormatterTest} @@ -11,21 +12,21 @@ public class CapitalizeFormatterTest { private CapitalizeFormatter formatter; - @Before + @BeforeEach public void setUp() { formatter = new CapitalizeFormatter(); } @Test public void test() { - Assert.assertEquals("Upper Each First", formatter.format("upper each First")); - Assert.assertEquals("Upper Each First {NOT} {this}", formatter.format("upper each first {NOT} {this}")); - Assert.assertEquals("Upper Each First {N}ot {t}his", formatter.format("upper each first {N}OT {t}his")); + assertEquals("Upper Each First", formatter.format("upper each First")); + assertEquals("Upper Each First {NOT} {this}", formatter.format("upper each first {NOT} {this}")); + assertEquals("Upper Each First {N}ot {t}his", formatter.format("upper each first {N}OT {t}his")); } @Test public void formatExample() { - Assert.assertEquals("I Have {a} Dream", formatter.format(formatter.getExampleInput())); + assertEquals("I Have {a} Dream", formatter.format(formatter.getExampleInput())); } } diff --git a/src/test/java/org/jabref/logic/formatter/casechanger/LowerCaseFormatterTest.java b/src/test/java/org/jabref/logic/formatter/casechanger/LowerCaseFormatterTest.java index 6ed971cf0ab..acfe250974c 100644 --- a/src/test/java/org/jabref/logic/formatter/casechanger/LowerCaseFormatterTest.java +++ b/src/test/java/org/jabref/logic/formatter/casechanger/LowerCaseFormatterTest.java @@ -1,8 +1,9 @@ package org.jabref.logic.formatter.casechanger; -import org.junit.Assert; import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; /** * Tests in addition to the general tests from {@link org.jabref.logic.formatter.FormatterTest} @@ -18,14 +19,14 @@ public void setUp() { @Test public void test() { - Assert.assertEquals("lower", formatter.format("LOWER")); - Assert.assertEquals("lower {UPPER}", formatter.format("LOWER {UPPER}")); - Assert.assertEquals("lower {U}pper", formatter.format("LOWER {U}PPER")); + assertEquals("lower", formatter.format("LOWER")); + assertEquals("lower {UPPER}", formatter.format("LOWER {UPPER}")); + assertEquals("lower {U}pper", formatter.format("LOWER {U}PPER")); } @Test public void formatExample() { - Assert.assertEquals("kde {Amarok}", formatter.format(formatter.getExampleInput())); + assertEquals("kde {Amarok}", formatter.format(formatter.getExampleInput())); } } diff --git a/src/test/java/org/jabref/logic/formatter/casechanger/ProtectTermsFormatterTest.java b/src/test/java/org/jabref/logic/formatter/casechanger/ProtectTermsFormatterTest.java index c2cca494c04..c6fcb1fafd7 100644 --- a/src/test/java/org/jabref/logic/formatter/casechanger/ProtectTermsFormatterTest.java +++ b/src/test/java/org/jabref/logic/formatter/casechanger/ProtectTermsFormatterTest.java @@ -5,11 +5,10 @@ import org.jabref.logic.protectedterms.ProtectedTermsLoader; import org.jabref.logic.protectedterms.ProtectedTermsPreferences; -import org.junit.Before; -import org.junit.Test; - -import static org.junit.Assert.assertEquals; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; /** * Tests in addition to the general tests from {@link org.jabref.logic.formatter.FormatterTest} @@ -18,7 +17,7 @@ public class ProtectTermsFormatterTest { private ProtectTermsFormatter formatter; - @Before + @BeforeEach public void setUp() { ProtectTermsFormatter .setProtectedTermsLoader( diff --git a/src/test/java/org/jabref/logic/formatter/casechanger/SentenceCaseFormatterTest.java b/src/test/java/org/jabref/logic/formatter/casechanger/SentenceCaseFormatterTest.java index 63fcdde8835..9e03374df67 100644 --- a/src/test/java/org/jabref/logic/formatter/casechanger/SentenceCaseFormatterTest.java +++ b/src/test/java/org/jabref/logic/formatter/casechanger/SentenceCaseFormatterTest.java @@ -1,9 +1,9 @@ package org.jabref.logic.formatter.casechanger; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; /** * Tests in addition to the general tests from {@link org.jabref.logic.formatter.FormatterTest} @@ -12,22 +12,22 @@ public class SentenceCaseFormatterTest { private SentenceCaseFormatter formatter; - @Before + @BeforeEach public void setUp() { formatter = new SentenceCaseFormatter(); } @Test public void test() { - Assert.assertEquals("Upper first", formatter.format("upper First")); - Assert.assertEquals("Upper first", formatter.format("uPPER FIRST")); - Assert.assertEquals("Upper {NOT} first", formatter.format("upper {NOT} FIRST")); - Assert.assertEquals("Upper {N}ot first", formatter.format("upper {N}OT FIRST")); + assertEquals("Upper first", formatter.format("upper First")); + assertEquals("Upper first", formatter.format("uPPER FIRST")); + assertEquals("Upper {NOT} first", formatter.format("upper {NOT} FIRST")); + assertEquals("Upper {N}ot first", formatter.format("upper {N}OT FIRST")); } @Test public void formatExample() { - Assert.assertEquals("I have {Aa} dream", formatter.format(formatter.getExampleInput())); + assertEquals("I have {Aa} dream", formatter.format(formatter.getExampleInput())); } } diff --git a/src/test/java/org/jabref/logic/formatter/casechanger/TitleCaseFormatterTest.java b/src/test/java/org/jabref/logic/formatter/casechanger/TitleCaseFormatterTest.java index 1050757c216..faccd196267 100644 --- a/src/test/java/org/jabref/logic/formatter/casechanger/TitleCaseFormatterTest.java +++ b/src/test/java/org/jabref/logic/formatter/casechanger/TitleCaseFormatterTest.java @@ -1,8 +1,9 @@ package org.jabref.logic.formatter.casechanger; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; /** * Tests in addition to the general tests from {@link org.jabref.logic.formatter.FormatterTest} @@ -11,77 +12,77 @@ public class TitleCaseFormatterTest { private TitleCaseFormatter formatter; - @Before + @BeforeEach public void setUp() { formatter = new TitleCaseFormatter(); } @Test public void eachFirstLetterIsUppercased() { - Assert.assertEquals("Upper Each First", formatter.format("upper each first")); + assertEquals("Upper Each First", formatter.format("upper each first")); } @Test public void eachFirstLetterIsUppercasedAndOthersLowercased() { - Assert.assertEquals("Upper Each First", formatter.format("upper eACH first")); + assertEquals("Upper Each First", formatter.format("upper eACH first")); } @Test public void eachFirstLetterIsUppercasedAndATralingAndIsAlsoUppercased() { - Assert.assertEquals("An Upper Each First And", formatter.format("an upper each first and")); + assertEquals("An Upper Each First And", formatter.format("an upper each first and")); } @Test public void eachFirstLetterIsUppercasedAndATralingAndIsAlsoCorrectlyCased() { - Assert.assertEquals("An Upper Each First And", formatter.format("an upper each first AND")); + assertEquals("An Upper Each First And", formatter.format("an upper each first AND")); } @Test - public void eachFirstLetterIsUppercasedButIntermediateAndsAreKeptLowercase(){ - Assert.assertEquals("An Upper Each of the and First And", + public void eachFirstLetterIsUppercasedButIntermediateAndsAreKeptLowercase() { + assertEquals("An Upper Each of the and First And", formatter.format("an upper each of the and first and")); } @Test - public void eachFirstLetterIsUppercasedButIntermediateAndsArePutLowercase(){ - Assert.assertEquals("An Upper Each of the and First And", + public void eachFirstLetterIsUppercasedButIntermediateAndsArePutLowercase() { + assertEquals("An Upper Each of the and First And", formatter.format("an upper each of the AND first and")); } @Test public void theAfterColonGetsCapitalized() { - Assert.assertEquals("An Upper Each of: The and First And", + assertEquals("An Upper Each of: The and First And", formatter.format("an upper each of: the and first and")); } @Test public void completeWordsInCurlyBracketsIsLeftUnchanged() { - Assert.assertEquals("An Upper First with and without {CURLY} {brackets}", + assertEquals("An Upper First with and without {CURLY} {brackets}", formatter.format("AN UPPER FIRST WITH AND WITHOUT {CURLY} {brackets}")); } @Test public void lettersInCurlyBracketsIsLeftUnchanged() { - Assert.assertEquals("An Upper First with {A}nd without {C}urly {b}rackets", + assertEquals("An Upper First with {A}nd without {C}urly {b}rackets", formatter.format("AN UPPER FIRST WITH {A}ND WITHOUT {C}URLY {b}rackets")); } @Test public void intraWordLettersInCurlyBracketsIsLeftUnchanged() { - Assert.assertEquals("{b}rackets {b}rac{K}ets Brack{E}ts", + assertEquals("{b}rackets {b}rac{K}ets Brack{E}ts", formatter.format("{b}RaCKeTS {b}RaC{K}eTS bRaCK{E}ts")); } @Test public void testTwoExperiencesTitle() { - Assert.assertEquals( - "Two Experiences Designing for Effective Security", - formatter.format("Two experiences designing for effective security")); + assertEquals( + "Two Experiences Designing for Effective Security", + formatter.format("Two experiences designing for effective security")); } @Test public void formatExample() { - Assert.assertEquals("{BPMN} Conformance in Open Source Engines", formatter.format(formatter.getExampleInput())); + assertEquals("{BPMN} Conformance in Open Source Engines", formatter.format(formatter.getExampleInput())); } } diff --git a/src/test/java/org/jabref/logic/formatter/casechanger/UpperCaseFormatterTest.java b/src/test/java/org/jabref/logic/formatter/casechanger/UpperCaseFormatterTest.java index ae247d1cab2..7b406defe37 100644 --- a/src/test/java/org/jabref/logic/formatter/casechanger/UpperCaseFormatterTest.java +++ b/src/test/java/org/jabref/logic/formatter/casechanger/UpperCaseFormatterTest.java @@ -1,8 +1,9 @@ package org.jabref.logic.formatter.casechanger; -import org.junit.Assert; -import org.junit.Before; import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; + +import static org.junit.jupiter.api.Assertions.assertEquals; /** @@ -12,22 +13,22 @@ public class UpperCaseFormatterTest { private UpperCaseFormatter formatter; - @Before + @BeforeEach public void setUp() { formatter = new UpperCaseFormatter(); } @Test public void test() { - Assert.assertEquals("LOWER", formatter.format("LOWER")); - Assert.assertEquals("UPPER", formatter.format("upper")); - Assert.assertEquals("UPPER", formatter.format("UPPER")); - Assert.assertEquals("UPPER {lower}", formatter.format("upper {lower}")); - Assert.assertEquals("UPPER {l}OWER", formatter.format("upper {l}ower")); + assertEquals("LOWER", formatter.format("LOWER")); + assertEquals("UPPER", formatter.format("upper")); + assertEquals("UPPER", formatter.format("UPPER")); + assertEquals("UPPER {lower}", formatter.format("upper {lower}")); + assertEquals("UPPER {l}OWER", formatter.format("upper {l}ower")); } @Test public void formatExample() { - Assert.assertEquals("KDE {Amarok}", formatter.format(formatter.getExampleInput())); + assertEquals("KDE {Amarok}", formatter.format(formatter.getExampleInput())); } } diff --git a/src/test/java/org/jabref/logic/formatter/minifier/MinifyNameListFormatterTest.java b/src/test/java/org/jabref/logic/formatter/minifier/MinifyNameListFormatterTest.java index ed26c55aa15..99a3146e3ed 100644 --- a/src/test/java/org/jabref/logic/formatter/minifier/MinifyNameListFormatterTest.java +++ b/src/test/java/org/jabref/logic/formatter/minifier/MinifyNameListFormatterTest.java @@ -1,8 +1,10 @@ package org.jabref.logic.formatter.minifier; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; /** * Tests in addition to the general tests from {@link org.jabref.logic.formatter.FormatterTest} @@ -11,7 +13,7 @@ public class MinifyNameListFormatterTest { private MinifyNameListFormatter formatter; - @Before + @BeforeEach public void setUp() { formatter = new MinifyNameListFormatter(); } @@ -31,6 +33,6 @@ public void formatExample() { } private void expectCorrect(String input, String expected) { - Assert.assertEquals(expected, formatter.format(input)); + assertEquals(expected, formatter.format(input)); } } diff --git a/src/test/java/org/jabref/logic/help/HelpFileTest.java b/src/test/java/org/jabref/logic/help/HelpFileTest.java index e8ee9424478..0b97be002e1 100644 --- a/src/test/java/org/jabref/logic/help/HelpFileTest.java +++ b/src/test/java/org/jabref/logic/help/HelpFileTest.java @@ -6,12 +6,14 @@ import org.jabref.logic.net.URLDownload; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static junit.framework.TestCase.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class HelpFileTest { + private final String jabrefHelp = "https://help.jabref.org/en/"; + @Test public void referToValidPage() throws IOException { for (HelpFile help : HelpFile.values()) { diff --git a/src/test/java/org/jabref/logic/importer/BibDatabaseTestsWithFiles.java b/src/test/java/org/jabref/logic/importer/BibDatabaseTestsWithFiles.java index 8e39ab16e3e..fe4877764cb 100644 --- a/src/test/java/org/jabref/logic/importer/BibDatabaseTestsWithFiles.java +++ b/src/test/java/org/jabref/logic/importer/BibDatabaseTestsWithFiles.java @@ -9,8 +9,8 @@ import org.jabref.model.database.BibDatabase; import org.jabref.model.util.DummyFileUpdateMonitor; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.mockito.Answers; import static org.junit.Assert.assertEquals; @@ -20,7 +20,7 @@ public class BibDatabaseTestsWithFiles { private ImportFormatPreferences importFormatPreferences; - @Before + @BeforeEach public void setUp() { importFormatPreferences = mock(ImportFormatPreferences.class, Answers.RETURNS_DEEP_STUBS); } diff --git a/src/test/java/org/jabref/logic/importer/DatabaseFileLookupTest.java b/src/test/java/org/jabref/logic/importer/DatabaseFileLookupTest.java index f7ac12347f3..999123b752e 100644 --- a/src/test/java/org/jabref/logic/importer/DatabaseFileLookupTest.java +++ b/src/test/java/org/jabref/logic/importer/DatabaseFileLookupTest.java @@ -10,11 +10,12 @@ import org.jabref.model.entry.BibEntry; import org.jabref.model.util.DummyFileUpdateMonitor; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.mockito.Answers; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.mockito.Mockito.mock; /** @@ -30,7 +31,7 @@ public class DatabaseFileLookupTest { private BibEntry entry2; - @Before + @BeforeEach public void setUp() throws Exception { try (FileInputStream stream = new FileInputStream(ImportDataTest.UNLINKED_FILES_TEST_BIB); InputStreamReader reader = new InputStreamReader(stream, StandardCharsets.UTF_8)) { @@ -48,10 +49,10 @@ public void setUp() throws Exception { */ @Test public void testTestDatabase() { - Assert.assertEquals(2, database.getEntryCount()); - Assert.assertEquals(2, entries.size()); - Assert.assertNotNull(entry1); - Assert.assertNotNull(entry2); + assertEquals(2, database.getEntryCount()); + assertEquals(2, entries.size()); + assertNotNull(entry1); + assertNotNull(entry2); } } diff --git a/src/test/java/org/jabref/logic/importer/ImportDataTest.java b/src/test/java/org/jabref/logic/importer/ImportDataTest.java index 53cbda75a65..a106633c567 100644 --- a/src/test/java/org/jabref/logic/importer/ImportDataTest.java +++ b/src/test/java/org/jabref/logic/importer/ImportDataTest.java @@ -3,8 +3,10 @@ import java.io.File; import java.nio.file.Paths; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; /** * @author Nosh&Dan @@ -32,20 +34,20 @@ public class ImportDataTest { @Test public void testTestingEnvironment() { - Assert.assertTrue(ImportDataTest.EXISTING_FOLDER.exists()); - Assert.assertTrue(ImportDataTest.EXISTING_FOLDER.isDirectory()); + assertTrue(ImportDataTest.EXISTING_FOLDER.exists()); + assertTrue(ImportDataTest.EXISTING_FOLDER.isDirectory()); - Assert.assertTrue(ImportDataTest.FILE_IN_DATABASE.exists()); - Assert.assertTrue(ImportDataTest.FILE_IN_DATABASE.isFile()); + assertTrue(ImportDataTest.FILE_IN_DATABASE.exists()); + assertTrue(ImportDataTest.FILE_IN_DATABASE.isFile()); - Assert.assertTrue(ImportDataTest.FILE_NOT_IN_DATABASE.exists()); - Assert.assertTrue(ImportDataTest.FILE_NOT_IN_DATABASE.isFile()); + assertTrue(ImportDataTest.FILE_NOT_IN_DATABASE.exists()); + assertTrue(ImportDataTest.FILE_NOT_IN_DATABASE.isFile()); } @Test public void testOpenNotExistingDirectory() { - Assert.assertFalse(ImportDataTest.NOT_EXISTING_FOLDER.exists()); - Assert.assertFalse(ImportDataTest.NOT_EXISTING_PDF.exists()); + assertFalse(ImportDataTest.NOT_EXISTING_FOLDER.exists()); + assertFalse(ImportDataTest.NOT_EXISTING_PDF.exists()); } } diff --git a/src/test/java/org/jabref/logic/importer/ImportFormatReaderTestParameterless.java b/src/test/java/org/jabref/logic/importer/ImportFormatReaderTestParameterless.java index 4aeb558d48b..a8336a40f2b 100644 --- a/src/test/java/org/jabref/logic/importer/ImportFormatReaderTestParameterless.java +++ b/src/test/java/org/jabref/logic/importer/ImportFormatReaderTestParameterless.java @@ -8,20 +8,20 @@ import org.jabref.model.util.DummyFileUpdateMonitor; import org.jabref.model.util.FileUpdateMonitor; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.mockito.Answers; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; public class ImportFormatReaderTestParameterless { private ImportFormatReader reader; - private FileUpdateMonitor fileMonitor = new DummyFileUpdateMonitor(); + private final FileUpdateMonitor fileMonitor = new DummyFileUpdateMonitor(); - @Before + @BeforeEach public void setUp() { reader = new ImportFormatReader(); ImportFormatPreferences importFormatPreferences = mock(ImportFormatPreferences.class, Answers.RETURNS_DEEP_STUBS); @@ -29,29 +29,26 @@ public void setUp() { reader.resetImportFormats(importFormatPreferences, mock(XMPPreferences.class), fileMonitor); } - @Test(expected = ImportException.class) + @Test public void importUnknownFormatThrowsExceptionIfNoMatchingImporterWasFound() throws Exception { Path file = Paths.get(ImportFormatReaderTestParameterless.class.getResource("fileformat/emptyFile.xml").toURI()); - reader.importUnknownFormat(file, fileMonitor); - fail(); + assertThrows(NullPointerException.class, () -> reader.importUnknownFormat(file, fileMonitor)); } - @Test(expected = NullPointerException.class) + @Test public void testNullImportUnknownFormatPath() throws Exception { - reader.importUnknownFormat(null, fileMonitor); - fail(); + assertThrows(NullPointerException.class, () -> reader.importUnknownFormat(null, fileMonitor)); + } - @Test(expected = NullPointerException.class) + @Test public void testNullImportUnknownFormatString() throws Exception { - reader.importUnknownFormat(null); - fail(); + assertThrows(NullPointerException.class, () -> reader.importUnknownFormat(null)); + } - @Test(expected = ImportException.class) public void importFromFileWithUnknownFormatThrowsException() throws Exception { - reader.importFromFile("someunknownformat", Paths.get("somepath")); - fail(); + assertThrows(NullPointerException.class, () -> reader.importFromFile("someunknownformat", Paths.get("somepath"))); } } diff --git a/src/test/java/org/jabref/logic/importer/OpenDatabaseTest.java b/src/test/java/org/jabref/logic/importer/OpenDatabaseTest.java index b5c657c12cb..47ca7b116dc 100644 --- a/src/test/java/org/jabref/logic/importer/OpenDatabaseTest.java +++ b/src/test/java/org/jabref/logic/importer/OpenDatabaseTest.java @@ -14,11 +14,11 @@ import org.jabref.model.util.DummyFileUpdateMonitor; import org.jabref.model.util.FileUpdateMonitor; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.mockito.Answers; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -31,7 +31,7 @@ public class OpenDatabaseTest { private final File bibHeader; private final File bibHeaderAndSignature; private final File bibEncodingWithoutNewline; - private FileUpdateMonitor fileMonitor = new DummyFileUpdateMonitor(); + private final FileUpdateMonitor fileMonitor = new DummyFileUpdateMonitor(); public OpenDatabaseTest() throws URISyntaxException { bibNoHeader = Paths.get(OpenDatabaseTest.class.getResource("headerless.bib").toURI()).toFile(); @@ -43,7 +43,7 @@ public OpenDatabaseTest() throws URISyntaxException { .get(OpenDatabaseTest.class.getResource("encodingWithoutNewline.bib").toURI()).toFile(); } - @Before + @BeforeEach public void setUp() { importFormatPreferences = mock(ImportFormatPreferences.class, Answers.RETURNS_DEEP_STUBS); when(importFormatPreferences.getEncoding()).thenReturn(StandardCharsets.UTF_8); @@ -52,27 +52,27 @@ public void setUp() { @Test public void useFallbackEncodingIfNoHeader() throws IOException { ParserResult result = OpenDatabase.loadDatabase(bibNoHeader, importFormatPreferences, fileMonitor); - Assert.assertEquals(defaultEncoding, result.getMetaData().getEncoding().get()); + assertEquals(defaultEncoding, result.getMetaData().getEncoding().get()); } @Test public void useFallbackEncodingIfUnknownHeader() throws IOException { ParserResult result = OpenDatabase.loadDatabase(bibWrongHeader, importFormatPreferences, fileMonitor); - Assert.assertEquals(defaultEncoding, result.getMetaData().getEncoding().get()); + assertEquals(defaultEncoding, result.getMetaData().getEncoding().get()); } @Test public void useSpecifiedEncoding() throws IOException { ParserResult result = OpenDatabase.loadDatabase(bibHeader, importFormatPreferences.withEncoding(StandardCharsets.US_ASCII), fileMonitor); - Assert.assertEquals(defaultEncoding, result.getMetaData().getEncoding().get()); + assertEquals(defaultEncoding, result.getMetaData().getEncoding().get()); } @Test public void useSpecifiedEncodingWithSignature() throws IOException { ParserResult result = OpenDatabase.loadDatabase(bibHeaderAndSignature, importFormatPreferences.withEncoding(StandardCharsets.US_ASCII), fileMonitor); - Assert.assertEquals(defaultEncoding, result.getMetaData().getEncoding().get()); + assertEquals(defaultEncoding, result.getMetaData().getEncoding().get()); } @Test @@ -81,8 +81,8 @@ public void entriesAreParsedNoHeader() throws IOException { BibDatabase db = result.getDatabase(); // Entry - Assert.assertEquals(1, db.getEntryCount()); - Assert.assertEquals(Optional.of("2014"), db.getEntryByKey("1").get().getField("year")); + assertEquals(1, db.getEntryCount()); + assertEquals(Optional.of("2014"), db.getEntryByKey("1").get().getField("year")); } @Test @@ -91,8 +91,8 @@ public void entriesAreParsedHeader() throws IOException { BibDatabase db = result.getDatabase(); // Entry - Assert.assertEquals(1, db.getEntryCount()); - Assert.assertEquals(Optional.of("2014"), db.getEntryByKey("1").get().getField("year")); + assertEquals(1, db.getEntryCount()); + assertEquals(Optional.of("2014"), db.getEntryByKey("1").get().getField("year")); } @Test @@ -101,8 +101,8 @@ public void entriesAreParsedHeaderAndSignature() throws IOException { BibDatabase db = result.getDatabase(); // Entry - Assert.assertEquals(1, db.getEntryCount()); - Assert.assertEquals(Optional.of("2014"), db.getEntryByKey("1").get().getField("year")); + assertEquals(1, db.getEntryCount()); + assertEquals(Optional.of("2014"), db.getEntryByKey("1").get().getField("year")); } /** @@ -111,15 +111,15 @@ public void entriesAreParsedHeaderAndSignature() throws IOException { @Test public void correctlyParseEncodingWithoutNewline() throws IOException { ParserResult result = OpenDatabase.loadDatabase(bibEncodingWithoutNewline, importFormatPreferences, fileMonitor); - Assert.assertEquals(StandardCharsets.US_ASCII, result.getMetaData().getEncoding().get()); + assertEquals(StandardCharsets.US_ASCII, result.getMetaData().getEncoding().get()); BibDatabase db = result.getDatabase(); - Assert.assertEquals(Optional.of("testPreamble"), db.getPreamble()); + assertEquals(Optional.of("testPreamble"), db.getPreamble()); Collection entries = db.getEntries(); - Assert.assertEquals(1, entries.size()); + assertEquals(1, entries.size()); BibEntry entry = entries.iterator().next(); - Assert.assertEquals(Optional.of("testArticle"), entry.getCiteKeyOptional()); + assertEquals(Optional.of("testArticle"), entry.getCiteKeyOptional()); } } diff --git a/src/test/java/org/jabref/logic/importer/util/ConvertLegacyExplicitGroupsTest.java b/src/test/java/org/jabref/logic/importer/util/ConvertLegacyExplicitGroupsTest.java index 87af078b8c1..a01fdec06dd 100644 --- a/src/test/java/org/jabref/logic/importer/util/ConvertLegacyExplicitGroupsTest.java +++ b/src/test/java/org/jabref/logic/importer/util/ConvertLegacyExplicitGroupsTest.java @@ -10,10 +10,10 @@ import org.jabref.model.groups.GroupHierarchyType; import org.jabref.model.groups.GroupTreeNode; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class ConvertLegacyExplicitGroupsTest { @@ -21,7 +21,7 @@ public class ConvertLegacyExplicitGroupsTest { private BibEntry entry; private ExplicitGroup group; - @Before + @BeforeEach public void setUp() throws Exception { action = new ConvertLegacyExplicitGroups(); diff --git a/src/test/java/org/jabref/logic/importer/util/GroupsParserTest.java b/src/test/java/org/jabref/logic/importer/util/GroupsParserTest.java index dd9385a736a..cccfd5af51f 100644 --- a/src/test/java/org/jabref/logic/importer/util/GroupsParserTest.java +++ b/src/test/java/org/jabref/logic/importer/util/GroupsParserTest.java @@ -20,15 +20,16 @@ import org.jabref.model.util.DummyFileUpdateMonitor; import org.jabref.model.util.FileUpdateMonitor; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; public class GroupsParserTest { private FileUpdateMonitor fileMonitor; - @Before + @BeforeEach public void setUp() throws Exception { fileMonitor = new DummyFileUpdateMonitor(); } @@ -56,9 +57,8 @@ public void HierarchicalDelimiterThatNeedsToBeEscaped() throws Exception { assertEquals(expected, parsed); } - @Test(expected = ParseException.class) public void fromStringThrowsParseExceptionForNotEscapedGroupName() throws Exception { - GroupsParser.fromString("ExplicitGroup:slit\\\\;0\\;mertsch_slit2_2007\\;;", ',', fileMonitor); + assertThrows(ParseException.class, () -> GroupsParser.fromString("ExplicitGroup:slit\\\\;0\\;mertsch_slit2_2007\\;;", ',', fileMonitor)); } @Test @@ -122,8 +122,7 @@ public void fromStringParsesTexGroup() throws Exception { assertEquals(expected, parsed); } - @Test(expected = ParseException.class) public void fromStringUnknownGroupThrowsException() throws Exception { - GroupsParser.fromString("0 UnknownGroup:myUnknownGroup;0;;1;;;;", ',', fileMonitor); + assertThrows(ParseException.class, () -> GroupsParser.fromString("0 UnknownGroup:myUnknownGroup;0;;1;;;;", ',', fileMonitor)); } } diff --git a/src/test/java/org/jabref/logic/importer/util/JSONEntryParserTest.java b/src/test/java/org/jabref/logic/importer/util/JSONEntryParserTest.java index ef8986c8501..86b52f2449d 100644 --- a/src/test/java/org/jabref/logic/importer/util/JSONEntryParserTest.java +++ b/src/test/java/org/jabref/logic/importer/util/JSONEntryParserTest.java @@ -5,8 +5,9 @@ import org.jabref.model.entry.BibEntry; import org.json.JSONObject; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; public class JSONEntryParserTest { @@ -27,15 +28,15 @@ public void testBibJSONConverter() { JSONObject jsonObject = new JSONObject(jsonString); BibEntry bibEntry = jc.parseBibJSONtoBibtex(jsonObject, ','); - Assert.assertEquals("article", bibEntry.getType()); - Assert.assertEquals(Optional.of("VLSI Design"), bibEntry.getField("journal")); - Assert.assertEquals(Optional.of("10.1155/2014/217495"), bibEntry.getField("doi")); - Assert.assertEquals(Optional.of("Syed Asad Alam and Oscar Gustafsson"), bibEntry.getField("author")); - Assert.assertEquals( + assertEquals("article", bibEntry.getType()); + assertEquals(Optional.of("VLSI Design"), bibEntry.getField("journal")); + assertEquals(Optional.of("10.1155/2014/217495"), bibEntry.getField("doi")); + assertEquals(Optional.of("Syed Asad Alam and Oscar Gustafsson"), bibEntry.getField("author")); + assertEquals( Optional.of( "Design of Finite Word Length Linear-Phase FIR Filters in the Logarithmic Number System Domain"), bibEntry.getField("title")); - Assert.assertEquals(Optional.of("2014"), bibEntry.getField("year")); + assertEquals(Optional.of("2014"), bibEntry.getField("year")); } @Test @@ -52,13 +53,13 @@ public void testSpringerJSONToBibtex() { JSONObject jsonObject = new JSONObject(jsonString); BibEntry bibEntry = JSONEntryParser.parseSpringerJSONtoBibtex(jsonObject); - Assert.assertEquals(Optional.of("1992"), bibEntry.getField("year")); - Assert.assertEquals(Optional.of("5"), bibEntry.getField("number")); - Assert.assertEquals(Optional.of("#sep#"), bibEntry.getField("month")); - Assert.assertEquals(Optional.of("10.1007/BF01201962"), bibEntry.getField("doi")); - Assert.assertEquals(Optional.of("8"), bibEntry.getField("volume")); - Assert.assertEquals(Optional.of("Springer"), bibEntry.getField("publisher")); - Assert.assertEquals(Optional.of("1992-09-01"), bibEntry.getField("date")); + assertEquals(Optional.of("1992"), bibEntry.getField("year")); + assertEquals(Optional.of("5"), bibEntry.getField("number")); + assertEquals(Optional.of("#sep#"), bibEntry.getField("month")); + assertEquals(Optional.of("10.1007/BF01201962"), bibEntry.getField("doi")); + assertEquals(Optional.of("8"), bibEntry.getField("volume")); + assertEquals(Optional.of("Springer"), bibEntry.getField("publisher")); + assertEquals(Optional.of("1992-09-01"), bibEntry.getField("date")); } } diff --git a/src/test/java/org/jabref/logic/integrity/BracesCorrectorTest.java b/src/test/java/org/jabref/logic/integrity/BracesCorrectorTest.java index 1535ece93b9..b14d6e5c49f 100644 --- a/src/test/java/org/jabref/logic/integrity/BracesCorrectorTest.java +++ b/src/test/java/org/jabref/logic/integrity/BracesCorrectorTest.java @@ -1,8 +1,9 @@ package org.jabref.logic.integrity; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; public class BracesCorrectorTest { diff --git a/src/test/java/org/jabref/logic/integrity/EntryLinkCheckerTest.java b/src/test/java/org/jabref/logic/integrity/EntryLinkCheckerTest.java index 241e5463072..81c8680abd0 100644 --- a/src/test/java/org/jabref/logic/integrity/EntryLinkCheckerTest.java +++ b/src/test/java/org/jabref/logic/integrity/EntryLinkCheckerTest.java @@ -6,13 +6,12 @@ import org.jabref.model.database.BibDatabase; import org.jabref.model.entry.BibEntry; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; -import static org.junit.Assert.fail; - +import static org.junit.jupiter.api.Assertions.assertThrows; public class EntryLinkCheckerTest { @@ -20,8 +19,7 @@ public class EntryLinkCheckerTest { private EntryLinkChecker checker; private BibEntry entry; - - @Before + @BeforeEach public void setUp() { database = new BibDatabase(); checker = new EntryLinkChecker(database); @@ -29,11 +27,9 @@ public void setUp() { database.insertEntry(entry); } - @SuppressWarnings("unused") - @Test(expected = NullPointerException.class) + @Test public void testEntryLinkChecker() { - new EntryLinkChecker(null); - fail(); + assertThrows(NullPointerException.class, () -> new EntryLinkChecker(null)); } @Test diff --git a/src/test/java/org/jabref/logic/integrity/NoBibTexFieldCheckerTest.java b/src/test/java/org/jabref/logic/integrity/NoBibTexFieldCheckerTest.java index ef751fefa8f..7539dc826a6 100644 --- a/src/test/java/org/jabref/logic/integrity/NoBibTexFieldCheckerTest.java +++ b/src/test/java/org/jabref/logic/integrity/NoBibTexFieldCheckerTest.java @@ -5,14 +5,14 @@ import org.jabref.model.entry.BibEntry; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class NoBibTexFieldCheckerTest { - private NoBibtexFieldChecker checker = new NoBibtexFieldChecker(); + private final NoBibtexFieldChecker checker = new NoBibtexFieldChecker(); @Test public void abstractIsNotRecognizedAsBiblatexOnlyField() { diff --git a/src/test/java/org/jabref/logic/integrity/PersonNamesCheckerTest.java b/src/test/java/org/jabref/logic/integrity/PersonNamesCheckerTest.java index 2f603389978..a5c21dbc8a1 100644 --- a/src/test/java/org/jabref/logic/integrity/PersonNamesCheckerTest.java +++ b/src/test/java/org/jabref/logic/integrity/PersonNamesCheckerTest.java @@ -5,16 +5,16 @@ import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.database.BibDatabaseMode; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class PersonNamesCheckerTest { private PersonNamesChecker checker; - @Before + @BeforeEach public void setUp() throws Exception { BibDatabaseContext databaseContext = new BibDatabaseContext(); databaseContext.setMode(BibDatabaseMode.BIBTEX); diff --git a/src/test/java/org/jabref/logic/journals/AbbreviationTest.java b/src/test/java/org/jabref/logic/journals/AbbreviationTest.java index dc284569776..cf1a769df72 100644 --- a/src/test/java/org/jabref/logic/journals/AbbreviationTest.java +++ b/src/test/java/org/jabref/logic/journals/AbbreviationTest.java @@ -1,9 +1,8 @@ package org.jabref.logic.journals; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; public class AbbreviationTest { @@ -46,8 +45,7 @@ public void testGetNextElementWithTrailingSpaces() { @Test public void testIsoAndMedlineAbbreviationsAreSame() { Abbreviation abbreviation = new Abbreviation(" Long Name ", " L N "); - - assertTrue(abbreviation.getIsoAbbreviation().equals(abbreviation.getMedlineAbbreviation())); + assertEquals(abbreviation.getIsoAbbreviation(), abbreviation.getMedlineAbbreviation()); } } diff --git a/src/test/java/org/jabref/logic/journals/JournalAbbreviationRepositoryTest.java b/src/test/java/org/jabref/logic/journals/JournalAbbreviationRepositoryTest.java index 822ce6d1ce3..f8c99cff5d4 100644 --- a/src/test/java/org/jabref/logic/journals/JournalAbbreviationRepositoryTest.java +++ b/src/test/java/org/jabref/logic/journals/JournalAbbreviationRepositoryTest.java @@ -1,17 +1,16 @@ package org.jabref.logic.journals; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; public class JournalAbbreviationRepositoryTest { @Test public void empty() { JournalAbbreviationRepository repository = new JournalAbbreviationRepository(); - assertEquals(0, repository.size()); assertTrue(repository.getAbbreviations().isEmpty()); } diff --git a/src/test/java/org/jabref/logic/journals/ShippedJournalAbbreviationDuplicateTest.java b/src/test/java/org/jabref/logic/journals/ShippedJournalAbbreviationDuplicateTest.java index 8c573304ede..dbff021a2df 100644 --- a/src/test/java/org/jabref/logic/journals/ShippedJournalAbbreviationDuplicateTest.java +++ b/src/test/java/org/jabref/logic/journals/ShippedJournalAbbreviationDuplicateTest.java @@ -1,7 +1,8 @@ package org.jabref.logic.journals; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertFalse; public class ShippedJournalAbbreviationDuplicateTest { @@ -10,11 +11,11 @@ public void noDuplicatesInShippedIEEEOfficialJournalAbbreviations() { JournalAbbreviationRepository repoBuiltIn = new JournalAbbreviationRepository(); repoBuiltIn.addEntries(JournalAbbreviationLoader.getBuiltInAbbreviations()); - for (Abbreviation abbreviation : JournalAbbreviationLoader.getOfficialIEEEAbbreviations()) { - Assert.assertFalse("duplicate name " + abbreviation.toString(), repoBuiltIn.getAbbreviation(abbreviation.getName()).isPresent()); - Assert.assertFalse("duplicate iso " + abbreviation.toString(), repoBuiltIn.getAbbreviation(abbreviation.getIsoAbbreviation()).isPresent()); - Assert.assertFalse("duplicate medline " + abbreviation.toString(), repoBuiltIn.getAbbreviation(abbreviation.getMedlineAbbreviation()).isPresent()); - } + JournalAbbreviationLoader.getOfficialIEEEAbbreviations().parallelStream().forEach(abbreviation -> { + assertFalse(repoBuiltIn.getAbbreviation(abbreviation.getName()).isPresent()); + assertFalse(repoBuiltIn.getAbbreviation(abbreviation.getIsoAbbreviation()).isPresent(), "duplicate iso " + abbreviation.toString()); + assertFalse(repoBuiltIn.getAbbreviation(abbreviation.getMedlineAbbreviation()).isPresent(), "duplicate medline " + abbreviation.toString()); + }); } @Test @@ -22,11 +23,11 @@ public void noDuplicatesInShippedIEEEStandardJournalAbbreviations() { JournalAbbreviationRepository repoBuiltIn = new JournalAbbreviationRepository(); repoBuiltIn.addEntries(JournalAbbreviationLoader.getBuiltInAbbreviations()); - for (Abbreviation abbreviation : JournalAbbreviationLoader.getStandardIEEEAbbreviations()) { - Assert.assertFalse("duplicate name " + abbreviation.toString(), repoBuiltIn.getAbbreviation(abbreviation.getName()).isPresent()); - Assert.assertFalse("duplicate iso " + abbreviation.toString(), repoBuiltIn.getAbbreviation(abbreviation.getIsoAbbreviation()).isPresent()); - Assert.assertFalse("duplicate medline " + abbreviation.toString(), repoBuiltIn.getAbbreviation(abbreviation.getMedlineAbbreviation()).isPresent()); - } + JournalAbbreviationLoader.getStandardIEEEAbbreviations().parallelStream().forEach(abbreviation -> { + assertFalse(repoBuiltIn.getAbbreviation(abbreviation.getName()).isPresent(), "duplicate name " + abbreviation.toString()); + assertFalse(repoBuiltIn.getAbbreviation(abbreviation.getIsoAbbreviation()).isPresent(), "duplicate iso " + abbreviation.toString()); + assertFalse(repoBuiltIn.getAbbreviation(abbreviation.getMedlineAbbreviation()).isPresent(), "duplicate medline " + abbreviation.toString()); + }); } } diff --git a/src/test/java/org/jabref/logic/l10n/EncodingsTest.java b/src/test/java/org/jabref/logic/l10n/EncodingsTest.java index 09172b61908..ed737b77fde 100644 --- a/src/test/java/org/jabref/logic/l10n/EncodingsTest.java +++ b/src/test/java/org/jabref/logic/l10n/EncodingsTest.java @@ -1,9 +1,9 @@ package org.jabref.logic.l10n; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; public class EncodingsTest { @Test diff --git a/src/test/java/org/jabref/logic/l10n/LanguagesTest.java b/src/test/java/org/jabref/logic/l10n/LanguagesTest.java index b5ba7710fc2..9df1198cbfa 100644 --- a/src/test/java/org/jabref/logic/l10n/LanguagesTest.java +++ b/src/test/java/org/jabref/logic/l10n/LanguagesTest.java @@ -3,10 +3,11 @@ import java.util.Locale; import java.util.Optional; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; public class LanguagesTest { @@ -47,8 +48,7 @@ public void convertUnknownKnownLanguageAndUnknownCountry() { assertEquals(Optional.empty(), Languages.convertToSupportedLocale("language_country_variant")); } - @Test(expected = NullPointerException.class) public void convertToKnownLocaleNull() { - Languages.convertToSupportedLocale(null); + assertThrows(NullPointerException.class, () -> Languages.convertToSupportedLocale(null)); } } diff --git a/src/test/java/org/jabref/logic/l10n/LocalizationConsistencyTest.java b/src/test/java/org/jabref/logic/l10n/LocalizationConsistencyTest.java index 06cdc43d995..4fb752c563e 100644 --- a/src/test/java/org/jabref/logic/l10n/LocalizationConsistencyTest.java +++ b/src/test/java/org/jabref/logic/l10n/LocalizationConsistencyTest.java @@ -20,11 +20,10 @@ import java.util.stream.Collectors; import com.google.common.collect.Sets; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; public class LocalizationConsistencyTest { @@ -42,8 +41,7 @@ public void allFilesMustBeInLanguages() throws IOException { } } } - Assert.assertEquals("There are some localization files that are not present in org.jabref.logic.l10n.Languages or vice versa!", - Collections.emptySet(), Sets.symmetricDifference(new HashSet<>(Languages.LANGUAGES.values()), localizationFiles)); + assertEquals(Collections.emptySet(), Sets.symmetricDifference(new HashSet<>(Languages.LANGUAGES.values()), localizationFiles), "There are some localization files that are not present in org.jabref.logic.l10n.Languages or vice versa!"); } } @@ -56,7 +54,7 @@ public void ensureNoDuplicates() { // read in DuplicationDetectionProperties properties = new DuplicationDetectionProperties(); try (InputStream is = LocalizationConsistencyTest.class.getResourceAsStream(propertyFilePath); - InputStreamReader reader = new InputStreamReader(is, StandardCharsets.UTF_8)) { + InputStreamReader reader = new InputStreamReader(is, StandardCharsets.UTF_8)) { properties.load(reader); } catch (IOException e) { throw new RuntimeException(e); @@ -64,7 +62,7 @@ public void ensureNoDuplicates() { List duplicates = properties.getDuplicates(); - assertEquals("Duplicate keys inside bundle " + bundle + "_" + lang, Collections.emptyList(), duplicates); + assertEquals(Collections.emptyList(), duplicates, "Duplicate keys inside bundle " + bundle + "_" + lang); } } } @@ -99,60 +97,57 @@ public void languageKeysShouldNotBeQuotedInFiles() throws IOException { .stream() .filter(key -> key.getKey().contains("_") && key.getKey().equals(new LocalizationKey(key.getKey()).getPropertiesKey())) .collect(Collectors.toList()); - Assert.assertEquals( - "Language keys must not be used quoted in code! Use \"This is a message\" instead of \"This_is_a_message\".\n" + - "Please correct the following entries:\n" + - quotedEntries - .stream() - .map(key -> String.format("\n%s (%s)\n", key.getKey(), key.getPath())) - .collect(Collectors.toList()) - , - Collections.EMPTY_LIST, quotedEntries); + assertEquals(Collections.EMPTY_LIST, quotedEntries, "Language keys must not be used quoted in code! Use \"This is a message\" instead of \"This_is_a_message\".\n" + + "Please correct the following entries:\n" + + quotedEntries + .stream() + .map(key -> String.format("\n%s (%s)\n", key.getKey(), key.getPath())) + .collect(Collectors.toList())); } @Test public void findMissingLocalizationKeys() throws IOException { - List missingKeys = LocalizationParser.find(LocalizationBundleForTest.LANG).stream().sorted() - .distinct().collect(Collectors.toList()); - - assertEquals("DETECTED LANGUAGE KEYS WHICH ARE NOT IN THE ENGLISH LANGUAGE FILE\n" + - "PASTE THESE INTO THE ENGLISH LANGUAGE FILE\n" + - missingKeys.parallelStream() - .map(key -> String.format("\n%s=%s\n", key.getKey(), key.getKey().replaceAll("\\\\ ", " "))) - .collect(Collectors.toList()), - Collections.emptyList(), missingKeys); + List missingKeys = LocalizationParser.find(LocalizationBundleForTest.LANG) + .stream() + .sorted() + .distinct() + .collect(Collectors.toList()); + + assertEquals(Collections.emptyList(), missingKeys, "DETECTED LANGUAGE KEYS WHICH ARE NOT IN THE ENGLISH LANGUAGE FILE\n" + + "PASTE THESE INTO THE ENGLISH LANGUAGE FILE\n" + + missingKeys.parallelStream() + .map(key -> String.format("\n%s=%s\n", key.getKey(), key.getKey().replaceAll("\\\\ ", " "))) + .collect(Collectors.toList())); } @Test public void findMissingMenuLocalizationKeys() throws IOException { Set missingKeys = LocalizationParser.find(LocalizationBundleForTest.MENU); - assertEquals("DETECTED LANGUAGE KEYS WHICH ARE NOT IN THE ENGLISH MENU FILE\n" + - "PASTE THESE INTO THE ENGLISH MENU FILE\n" + - missingKeys.parallelStream() - .map(key -> String.format("%s=%s", key.getKey(), key.getKey())) - .collect(Collectors.toList()), - Collections.emptySet(), missingKeys); + assertEquals(Collections.emptySet(), missingKeys, "DETECTED LANGUAGE KEYS WHICH ARE NOT IN THE ENGLISH MENU FILE\n" + + "PASTE THESE INTO THE ENGLISH MENU FILE\n" + + missingKeys.parallelStream() + .map(key -> String.format("%s=%s", key.getKey(), key.getKey())) + .collect(Collectors.toList())); } @Test public void findObsoleteLocalizationKeys() throws IOException { Set obsoleteKeys = LocalizationParser.findObsolete(LocalizationBundleForTest.LANG); - assertEquals("Obsolete keys found in language properties file: " + obsoleteKeys + "\n" + - "1. CHECK IF THE KEY IS REALLY NOT USED ANYMORE\n" + - "2. REMOVE THESE FROM THE ENGLISH LANGUAGE FILE\n", - Collections.emptySet(), obsoleteKeys); + assertEquals(Collections.emptySet(), obsoleteKeys, "Obsolete keys found in language properties file: " + obsoleteKeys + "\n" + + "1. CHECK IF THE KEY IS REALLY NOT USED ANYMORE\n" + + "2. REMOVE THESE FROM THE ENGLISH LANGUAGE FILE\n"); } @Test public void findObsoleteMenuLocalizationKeys() throws IOException { Set obsoleteKeys = LocalizationParser.findObsolete(LocalizationBundleForTest.MENU); - assertEquals("Obsolete keys found in the menu properties file: " + obsoleteKeys + "\n" + + assertEquals( + Collections.emptySet(), obsoleteKeys, "Obsolete keys found in the menu properties file: " + obsoleteKeys + "\n" + "1. CHECK IF THE KEY IS REALLY NOT USED ANYMORE\n" + - "2. REMOVE THESE FROM THE ENGLISH MENU FILE\n", - Collections.emptySet(), obsoleteKeys); + "2. REMOVE THESE FROM THE ENGLISH MENU FILE\n"); } @Test @@ -163,18 +158,17 @@ public void localizationParameterMustIncludeAString() throws IOException { // Localization.lang("Problem downloading from %1", address) Set keys = LocalizationParser.findLocalizationParametersStringsInJavaFiles(LocalizationBundleForTest.LANG); for (LocalizationEntry e : keys) { - assertTrue("Illegal localization parameter found. Must include a String with potential concatenation or replacement parameters. Illegal parameter: Localization.lang(" + e.getKey(), - e.getKey().startsWith("\"") || e.getKey().endsWith("\"")); + assertTrue(e.getKey().startsWith("\"") || e.getKey().endsWith("\""), "Illegal localization parameter found. Must include a String with potential concatenation or replacement parameters. Illegal parameter: Localization.lang(" + e.getKey()); } keys = LocalizationParser.findLocalizationParametersStringsInJavaFiles(LocalizationBundleForTest.MENU); for (LocalizationEntry e : keys) { - assertTrue("Illegal localization parameter found. Must include a String with potential concatenation or replacement parameters. Illegal parameter: Localization.lang(" + e.getKey(), - e.getKey().startsWith("\"") || e.getKey().endsWith("\"")); + assertTrue(e.getKey().startsWith("\"") || e.getKey().endsWith("\""), "Illegal localization parameter found. Must include a String with potential concatenation or replacement parameters. Illegal parameter: Localization.lang(" + e.getKey()); } } private static class DuplicationDetectionProperties extends Properties { + private static final long serialVersionUID = 1L; private final List duplicates = new ArrayList<>(); diff --git a/src/test/java/org/jabref/logic/l10n/LocalizationKeyParamsTest.java b/src/test/java/org/jabref/logic/l10n/LocalizationKeyParamsTest.java index 7cdf4f58fcd..e64146731e3 100644 --- a/src/test/java/org/jabref/logic/l10n/LocalizationKeyParamsTest.java +++ b/src/test/java/org/jabref/logic/l10n/LocalizationKeyParamsTest.java @@ -1,8 +1,9 @@ package org.jabref.logic.l10n; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; public class LocalizationKeyParamsTest { @@ -15,9 +16,8 @@ public void testReplacePlaceholders() { assertEquals("What \n : %e %c_a b", new LocalizationKeyParams("What \n : %e %c_%0 %1", "a", "b").replacePlaceholders()); } - @Test(expected = IllegalStateException.class) public void testTooManyParams() { - new LocalizationKeyParams("", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0"); + assertThrows(IllegalStateException.class, () -> new LocalizationKeyParams("", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0")); } } diff --git a/src/test/java/org/jabref/logic/l10n/LocalizationKeyTest.java b/src/test/java/org/jabref/logic/l10n/LocalizationKeyTest.java index 838777f9830..2350512b37b 100644 --- a/src/test/java/org/jabref/logic/l10n/LocalizationKeyTest.java +++ b/src/test/java/org/jabref/logic/l10n/LocalizationKeyTest.java @@ -2,7 +2,7 @@ import org.junit.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class LocalizationKeyTest { diff --git a/src/test/java/org/jabref/logic/l10n/LocalizationParserTest.java b/src/test/java/org/jabref/logic/l10n/LocalizationParserTest.java index 17ae4d0e381..2463a15cdc6 100644 --- a/src/test/java/org/jabref/logic/l10n/LocalizationParserTest.java +++ b/src/test/java/org/jabref/logic/l10n/LocalizationParserTest.java @@ -4,9 +4,9 @@ import java.util.Collections; import java.util.List; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class LocalizationParserTest { diff --git a/src/test/java/org/jabref/logic/l10n/LocalizationTest.java b/src/test/java/org/jabref/logic/l10n/LocalizationTest.java index 8342a774492..e139735abd6 100644 --- a/src/test/java/org/jabref/logic/l10n/LocalizationTest.java +++ b/src/test/java/org/jabref/logic/l10n/LocalizationTest.java @@ -2,9 +2,9 @@ import java.util.Locale; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import static org.junit.Assert.assertEquals; @@ -12,12 +12,12 @@ public class LocalizationTest { private Locale locale; - @Before + @BeforeEach public void storeDefaultLocale() { locale = Locale.getDefault(); } - @After + @AfterEach public void restoreDefaultLocale() { Locale.setDefault(locale); javax.swing.JComponent.setDefaultLocale(locale); diff --git a/src/test/java/org/jabref/logic/l10n/PropertiesLocaleCompletenessTest.java b/src/test/java/org/jabref/logic/l10n/PropertiesLocaleCompletenessTest.java index ff42771cf02..d156107c1ca 100644 --- a/src/test/java/org/jabref/logic/l10n/PropertiesLocaleCompletenessTest.java +++ b/src/test/java/org/jabref/logic/l10n/PropertiesLocaleCompletenessTest.java @@ -12,9 +12,9 @@ import java.util.stream.Stream; import com.google.common.base.Splitter; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertTrue; /** * Checks that all property files are correctly encoded and can be loaded without errors. diff --git a/src/test/java/org/jabref/logic/layout/LayoutEntryTest.java b/src/test/java/org/jabref/logic/layout/LayoutEntryTest.java index b20af305c10..8a471d0d038 100644 --- a/src/test/java/org/jabref/logic/layout/LayoutEntryTest.java +++ b/src/test/java/org/jabref/logic/layout/LayoutEntryTest.java @@ -5,10 +5,10 @@ import org.jabref.model.entry.BibEntry; -import org.junit.Assert; -import org.junit.Before; import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.mock; /** @@ -38,7 +38,7 @@ public class LayoutEntryTest { /** * Initialize Preferences. */ - @Before + @BeforeEach public void setUp() { // create Bibtext Entry @@ -84,30 +84,30 @@ public String layout(String layoutFile, BibEntry entry) throws IOException { @Test public void testParseMethodCalls() { - Assert.assertEquals(1, LayoutEntry.parseMethodsCalls("bla").size()); - Assert.assertEquals("bla", (LayoutEntry.parseMethodsCalls("bla").get(0)).get(0)); + assertEquals(1, LayoutEntry.parseMethodsCalls("bla").size()); + assertEquals("bla", (LayoutEntry.parseMethodsCalls("bla").get(0)).get(0)); - Assert.assertEquals(1, LayoutEntry.parseMethodsCalls("bla,").size()); - Assert.assertEquals("bla", (LayoutEntry.parseMethodsCalls("bla,").get(0)).get(0)); + assertEquals(1, LayoutEntry.parseMethodsCalls("bla,").size()); + assertEquals("bla", (LayoutEntry.parseMethodsCalls("bla,").get(0)).get(0)); - Assert.assertEquals(1, LayoutEntry.parseMethodsCalls("_bla.bla.blub,").size()); - Assert.assertEquals("_bla.bla.blub", (LayoutEntry.parseMethodsCalls("_bla.bla.blub,").get(0)).get(0)); + assertEquals(1, LayoutEntry.parseMethodsCalls("_bla.bla.blub,").size()); + assertEquals("_bla.bla.blub", (LayoutEntry.parseMethodsCalls("_bla.bla.blub,").get(0)).get(0)); - Assert.assertEquals(2, LayoutEntry.parseMethodsCalls("bla,foo").size()); - Assert.assertEquals("bla", (LayoutEntry.parseMethodsCalls("bla,foo").get(0)).get(0)); - Assert.assertEquals("foo", (LayoutEntry.parseMethodsCalls("bla,foo").get(1)).get(0)); + assertEquals(2, LayoutEntry.parseMethodsCalls("bla,foo").size()); + assertEquals("bla", (LayoutEntry.parseMethodsCalls("bla,foo").get(0)).get(0)); + assertEquals("foo", (LayoutEntry.parseMethodsCalls("bla,foo").get(1)).get(0)); - Assert.assertEquals(2, LayoutEntry.parseMethodsCalls("bla(\"test\"),foo(\"fark\")").size()); - Assert.assertEquals("bla", (LayoutEntry.parseMethodsCalls("bla(\"test\"),foo(\"fark\")").get(0)).get(0)); - Assert.assertEquals("foo", (LayoutEntry.parseMethodsCalls("bla(\"test\"),foo(\"fark\")").get(1)).get(0)); - Assert.assertEquals("test", (LayoutEntry.parseMethodsCalls("bla(\"test\"),foo(\"fark\")").get(0)).get(1)); - Assert.assertEquals("fark", (LayoutEntry.parseMethodsCalls("bla(\"test\"),foo(\"fark\")").get(1)).get(1)); + assertEquals(2, LayoutEntry.parseMethodsCalls("bla(\"test\"),foo(\"fark\")").size()); + assertEquals("bla", (LayoutEntry.parseMethodsCalls("bla(\"test\"),foo(\"fark\")").get(0)).get(0)); + assertEquals("foo", (LayoutEntry.parseMethodsCalls("bla(\"test\"),foo(\"fark\")").get(1)).get(0)); + assertEquals("test", (LayoutEntry.parseMethodsCalls("bla(\"test\"),foo(\"fark\")").get(0)).get(1)); + assertEquals("fark", (LayoutEntry.parseMethodsCalls("bla(\"test\"),foo(\"fark\")").get(1)).get(1)); - Assert.assertEquals(2, LayoutEntry.parseMethodsCalls("bla(test),foo(fark)").size()); - Assert.assertEquals("bla", (LayoutEntry.parseMethodsCalls("bla(test),foo(fark)").get(0)).get(0)); - Assert.assertEquals("foo", (LayoutEntry.parseMethodsCalls("bla(test),foo(fark)").get(1)).get(0)); - Assert.assertEquals("test", (LayoutEntry.parseMethodsCalls("bla(test),foo(fark)").get(0)).get(1)); - Assert.assertEquals("fark", (LayoutEntry.parseMethodsCalls("bla(test),foo(fark)").get(1)).get(1)); + assertEquals(2, LayoutEntry.parseMethodsCalls("bla(test),foo(fark)").size()); + assertEquals("bla", (LayoutEntry.parseMethodsCalls("bla(test),foo(fark)").get(0)).get(0)); + assertEquals("foo", (LayoutEntry.parseMethodsCalls("bla(test),foo(fark)").get(1)).get(0)); + assertEquals("test", (LayoutEntry.parseMethodsCalls("bla(test),foo(fark)").get(0)).get(1)); + assertEquals("fark", (LayoutEntry.parseMethodsCalls("bla(test),foo(fark)").get(1)).get(1)); } } diff --git a/src/test/java/org/jabref/logic/layout/LayoutTest.java b/src/test/java/org/jabref/logic/layout/LayoutTest.java index 3430ccf02a9..9ce7d4093ff 100644 --- a/src/test/java/org/jabref/logic/layout/LayoutTest.java +++ b/src/test/java/org/jabref/logic/layout/LayoutTest.java @@ -13,22 +13,23 @@ import org.jabref.model.entry.BibEntry; import org.jabref.model.util.DummyFileUpdateMonitor; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.mockito.Answers; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; public class LayoutTest { + private static ImportFormatPreferences importFormatPreferences; private LayoutFormatterPreferences layoutFormatterPreferences; /** * Initialize Preferences. */ - @Before + @BeforeEach public void setUp() { layoutFormatterPreferences = mock(LayoutFormatterPreferences.class, Answers.RETURNS_DEEP_STUBS); importFormatPreferences = mock(ImportFormatPreferences.class, Answers.RETURNS_DEEP_STUBS); @@ -49,7 +50,7 @@ public String t1BibtexString() { public static BibEntry bibtexString2BibtexEntry(String s) throws IOException { ParserResult result = new BibtexParser(importFormatPreferences, new DummyFileUpdateMonitor()).parse(new StringReader(s)); Collection c = result.getDatabase().getEntries(); - Assert.assertEquals(1, c.size()); + assertEquals(1, c.size()); return c.iterator().next(); } @@ -63,9 +64,9 @@ public String layout(String layoutFile, String entry) throws IOException { @Test public void testLayoutBibtextype() throws IOException { - Assert.assertEquals("Unknown", layout("\\bibtextype", "@unknown{bla, author={This\nis\na\ntext}}")); - Assert.assertEquals("Article", layout("\\bibtextype", "@article{bla, author={This\nis\na\ntext}}")); - Assert.assertEquals("Misc", layout("\\bibtextype", "@misc{bla, author={This\nis\na\ntext}}")); + assertEquals("Unknown", layout("\\bibtextype", "@unknown{bla, author={This\nis\na\ntext}}")); + assertEquals("Article", layout("\\bibtextype", "@article{bla, author={This\nis\na\ntext}}")); + assertEquals("Misc", layout("\\bibtextype", "@misc{bla, author={This\nis\na\ntext}}")); } @Test @@ -73,12 +74,12 @@ public void testHTMLChar() throws IOException { String layoutText = layout("\\begin{author}\\format[HTMLChars]{\\author}\\end{author} ", "@other{bla, author={This\nis\na\ntext}}"); - Assert.assertEquals("This is a text ", layoutText); + assertEquals("This is a text ", layoutText); layoutText = layout("\\begin{author}\\format[HTMLChars]{\\author}\\end{author}", "@other{bla, author={This\nis\na\ntext}}"); - Assert.assertEquals("This is a text", layoutText); + assertEquals("This is a text", layoutText); } @Test @@ -86,7 +87,7 @@ public void testPluginLoading() throws IOException { String layoutText = layout("\\begin{author}\\format[NameFormatter]{\\author}\\end{author}", "@other{bla, author={Joe Doe and Jane, Moon}}"); - Assert.assertEquals("Joe Doe, Moon Jane", layoutText); + assertEquals("Joe Doe, Moon Jane", layoutText); } @Test @@ -94,7 +95,7 @@ public void testHTMLCharDoubleLineBreak() throws IOException { String layoutText = layout("\\begin{author}\\format[HTMLChars]{\\author}\\end{author} ", "@other{bla, author={This\nis\na\n\ntext}}"); - Assert.assertEquals("This is a text ", layoutText); + assertEquals("This is a text ", layoutText); } /** @@ -108,7 +109,7 @@ public void testLayout() throws IOException { "\\begin{abstract}

Abstract: \\format[HTMLChars]{\\abstract}\\end{abstract}
", t1BibtexString()); - Assert.assertEquals( + assertEquals( "

Abstract: ñ ñ í ı ı
", layoutText); } @@ -122,7 +123,7 @@ public void testWrapFileLinksLayout() throws IOException { String layoutText = layout("\\begin{file}\\format[WrapFileLinks(\\i. \\d (\\p))]{\\file}\\end{file}", "@other{bla, file={Test file:encrypted.pdf:PDF}}"); - Assert.assertEquals( + assertEquals( "1. Test file (" + new File("src/test/resources/pdfs/encrypted.pdf").getCanonicalPath() + ")", layoutText); } diff --git a/src/test/java/org/jabref/logic/layout/format/AuthorAbbreviatorTest.java b/src/test/java/org/jabref/logic/layout/format/AuthorAbbreviatorTest.java index bcaf5ec907b..9ae1cbc797c 100644 --- a/src/test/java/org/jabref/logic/layout/format/AuthorAbbreviatorTest.java +++ b/src/test/java/org/jabref/logic/layout/format/AuthorAbbreviatorTest.java @@ -2,8 +2,8 @@ import org.jabref.logic.layout.LayoutFormatter; -import org.junit.Assert; -import org.junit.Test; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; /** * Is the save as the AuthorLastFirstAbbreviator. @@ -16,10 +16,10 @@ public void testFormat() { LayoutFormatter a = new AuthorLastFirstAbbreviator(); LayoutFormatter b = new AuthorAbbreviator(); - Assert.assertEquals(b.format(""), a.format("")); - Assert.assertEquals(b.format("Someone, Van Something"), a.format("Someone, Van Something")); - Assert.assertEquals(b.format("Smith, John"), a.format("Smith, John")); - Assert.assertEquals(b.format("von Neumann, John and Smith, John and Black Brown, Peter"), a + assertEquals(b.format(""), a.format("")); + assertEquals(b.format("Someone, Van Something"), a.format("Someone, Van Something")); + assertEquals(b.format("Smith, John"), a.format("Smith, John")); + assertEquals(b.format("von Neumann, John and Smith, John and Black Brown, Peter"), a .format("von Neumann, John and Smith, John and Black Brown, Peter")); } diff --git a/src/test/java/org/jabref/logic/layout/format/AuthorAndToSemicolonReplacerTest.java b/src/test/java/org/jabref/logic/layout/format/AuthorAndToSemicolonReplacerTest.java index f4e0f2b85c0..8bbed1ac451 100644 --- a/src/test/java/org/jabref/logic/layout/format/AuthorAndToSemicolonReplacerTest.java +++ b/src/test/java/org/jabref/logic/layout/format/AuthorAndToSemicolonReplacerTest.java @@ -4,8 +4,8 @@ import java.util.Collection; import org.jabref.logic.layout.LayoutFormatter; -import org.junit.Assert; -import org.junit.Test; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameter; @@ -36,6 +36,6 @@ public static Collection data() { public void testFormat() { LayoutFormatter a = new AuthorAndToSemicolonReplacer(); - Assert.assertEquals(expected, a.format(input)); + assertEquals(expected, a.format(input)); } } diff --git a/src/test/java/org/jabref/logic/layout/format/AuthorAndsCommaReplacerTest.java b/src/test/java/org/jabref/logic/layout/format/AuthorAndsCommaReplacerTest.java index 1781d4fdc90..19a643988d0 100644 --- a/src/test/java/org/jabref/logic/layout/format/AuthorAndsCommaReplacerTest.java +++ b/src/test/java/org/jabref/logic/layout/format/AuthorAndsCommaReplacerTest.java @@ -2,8 +2,8 @@ import org.jabref.logic.layout.LayoutFormatter; -import org.junit.Assert; -import org.junit.Test; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class AuthorAndsCommaReplacerTest { @@ -17,17 +17,17 @@ public void testFormat() { LayoutFormatter a = new AuthorAndsCommaReplacer(); // Empty case - Assert.assertEquals("", a.format("")); + assertEquals("", a.format("")); // Single Names don't change - Assert.assertEquals("Someone, Van Something", a.format("Someone, Van Something")); + assertEquals("Someone, Van Something", a.format("Someone, Van Something")); // Two names just an & - Assert.assertEquals("John von Neumann & Peter Black Brown", + assertEquals("John von Neumann & Peter Black Brown", a.format("John von Neumann and Peter Black Brown")); // Three names put a comma: - Assert.assertEquals("von Neumann, John, Smith, John & Black Brown, Peter", + assertEquals("von Neumann, John, Smith, John & Black Brown, Peter", a.format("von Neumann, John and Smith, John and Black Brown, Peter")); } } diff --git a/src/test/java/org/jabref/logic/layout/format/AuthorAndsReplacerTest.java b/src/test/java/org/jabref/logic/layout/format/AuthorAndsReplacerTest.java index 9a7b6f088c4..44a85ca7ce6 100644 --- a/src/test/java/org/jabref/logic/layout/format/AuthorAndsReplacerTest.java +++ b/src/test/java/org/jabref/logic/layout/format/AuthorAndsReplacerTest.java @@ -2,8 +2,8 @@ import org.jabref.logic.layout.LayoutFormatter; -import org.junit.Assert; -import org.junit.Test; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class AuthorAndsReplacerTest { @@ -16,20 +16,20 @@ public void testFormat() { LayoutFormatter a = new AuthorAndsReplacer(); // Empty case - Assert.assertEquals("", a.format("")); + assertEquals("", a.format("")); // Single Names don't change - Assert.assertEquals("Someone, Van Something", a.format("Someone, Van Something")); + assertEquals("Someone, Van Something", a.format("Someone, Van Something")); // Two names just an & - Assert.assertEquals("John Smith & Black Brown, Peter", a + assertEquals("John Smith & Black Brown, Peter", a .format("John Smith and Black Brown, Peter")); // Three names put a comma: - Assert.assertEquals("von Neumann, John; Smith, John & Black Brown, Peter", a + assertEquals("von Neumann, John; Smith, John & Black Brown, Peter", a .format("von Neumann, John and Smith, John and Black Brown, Peter")); - Assert.assertEquals("John von Neumann; John Smith & Peter Black Brown", a + assertEquals("John von Neumann; John Smith & Peter Black Brown", a .format("John von Neumann and John Smith and Peter Black Brown")); } diff --git a/src/test/java/org/jabref/logic/layout/format/AuthorFirstAbbrLastCommasTest.java b/src/test/java/org/jabref/logic/layout/format/AuthorFirstAbbrLastCommasTest.java index b266c7a9cc4..9a91ff56c9b 100644 --- a/src/test/java/org/jabref/logic/layout/format/AuthorFirstAbbrLastCommasTest.java +++ b/src/test/java/org/jabref/logic/layout/format/AuthorFirstAbbrLastCommasTest.java @@ -2,8 +2,8 @@ import org.jabref.logic.layout.LayoutFormatter; -import org.junit.Assert; -import org.junit.Test; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class AuthorFirstAbbrLastCommasTest { @@ -12,20 +12,20 @@ public void testFormat() { LayoutFormatter a = new AuthorFirstAbbrLastCommas(); // Empty case - Assert.assertEquals("", a.format("")); + assertEquals("", a.format("")); // Single Names - Assert.assertEquals("V. S. Someone", a.format("Someone, Van Something")); + assertEquals("V. S. Someone", a.format("Someone, Van Something")); // Two names - Assert.assertEquals("J. von Neumann and P. Black Brown", a + assertEquals("J. von Neumann and P. Black Brown", a .format("John von Neumann and Black Brown, Peter")); // Three names - Assert.assertEquals("J. von Neumann, J. Smith and P. Black Brown", a + assertEquals("J. von Neumann, J. Smith and P. Black Brown", a .format("von Neumann, John and Smith, John and Black Brown, Peter")); - Assert.assertEquals("J. von Neumann, J. Smith and P. Black Brown", a + assertEquals("J. von Neumann, J. Smith and P. Black Brown", a .format("John von Neumann and John Smith and Black Brown, Peter")); } diff --git a/src/test/java/org/jabref/logic/layout/format/AuthorFirstAbbrLastOxfordCommasTest.java b/src/test/java/org/jabref/logic/layout/format/AuthorFirstAbbrLastOxfordCommasTest.java index 242b228f0a2..9871a0a9da5 100644 --- a/src/test/java/org/jabref/logic/layout/format/AuthorFirstAbbrLastOxfordCommasTest.java +++ b/src/test/java/org/jabref/logic/layout/format/AuthorFirstAbbrLastOxfordCommasTest.java @@ -2,8 +2,8 @@ import org.jabref.logic.layout.LayoutFormatter; -import org.junit.Assert; -import org.junit.Test; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class AuthorFirstAbbrLastOxfordCommasTest { @@ -15,20 +15,20 @@ public void testFormat() { LayoutFormatter a = new AuthorFirstAbbrLastOxfordCommas(); // Empty case - Assert.assertEquals("", a.format("")); + assertEquals("", a.format("")); // Single Names - Assert.assertEquals("V. S. Someone", a.format("Someone, Van Something")); + assertEquals("V. S. Someone", a.format("Someone, Van Something")); // Two names - Assert.assertEquals("J. von Neumann and P. Black Brown", a + assertEquals("J. von Neumann and P. Black Brown", a .format("John von Neumann and Black Brown, Peter")); // Three names - Assert.assertEquals("J. von Neumann, J. Smith, and P. Black Brown", a + assertEquals("J. von Neumann, J. Smith, and P. Black Brown", a .format("von Neumann, John and Smith, John and Black Brown, Peter")); - Assert.assertEquals("J. von Neumann, J. Smith, and P. Black Brown", a + assertEquals("J. von Neumann, J. Smith, and P. Black Brown", a .format("John von Neumann and John Smith and Black Brown, Peter")); } diff --git a/src/test/java/org/jabref/logic/layout/format/AuthorFirstFirstCommasTest.java b/src/test/java/org/jabref/logic/layout/format/AuthorFirstFirstCommasTest.java index 51f854a8fd4..97a9c29b82c 100644 --- a/src/test/java/org/jabref/logic/layout/format/AuthorFirstFirstCommasTest.java +++ b/src/test/java/org/jabref/logic/layout/format/AuthorFirstFirstCommasTest.java @@ -1,7 +1,7 @@ package org.jabref.logic.layout.format; -import org.junit.Assert; -import org.junit.Test; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class AuthorFirstFirstCommasTest { @@ -11,7 +11,7 @@ public class AuthorFirstFirstCommasTest { */ @Test public void testFormat() { - Assert.assertEquals("John von Neumann, John Smith and Peter Black Brown, Jr", + assertEquals("John von Neumann, John Smith and Peter Black Brown, Jr", new AuthorFirstFirstCommas() .format("von Neumann,,John and John Smith and Black Brown, Jr, Peter")); } diff --git a/src/test/java/org/jabref/logic/layout/format/AuthorFirstFirstTest.java b/src/test/java/org/jabref/logic/layout/format/AuthorFirstFirstTest.java index 315f512c9e5..d61d5840520 100644 --- a/src/test/java/org/jabref/logic/layout/format/AuthorFirstFirstTest.java +++ b/src/test/java/org/jabref/logic/layout/format/AuthorFirstFirstTest.java @@ -1,7 +1,7 @@ package org.jabref.logic.layout.format; -import org.junit.Assert; -import org.junit.Test; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class AuthorFirstFirstTest { @@ -11,7 +11,7 @@ public class AuthorFirstFirstTest { */ @Test public void testFormat() { - Assert.assertEquals("John von Neumann and John Smith and Peter Black Brown, Jr", + assertEquals("John von Neumann and John Smith and Peter Black Brown, Jr", new AuthorFirstFirst() .format("von Neumann,,John and John Smith and Black Brown, Jr, Peter")); } diff --git a/src/test/java/org/jabref/logic/layout/format/AuthorFirstLastCommasTest.java b/src/test/java/org/jabref/logic/layout/format/AuthorFirstLastCommasTest.java index aa3f83c5b57..8607bfffeb1 100644 --- a/src/test/java/org/jabref/logic/layout/format/AuthorFirstLastCommasTest.java +++ b/src/test/java/org/jabref/logic/layout/format/AuthorFirstLastCommasTest.java @@ -2,8 +2,8 @@ import org.jabref.logic.layout.LayoutFormatter; -import org.junit.Assert; -import org.junit.Test; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class AuthorFirstLastCommasTest { @@ -15,20 +15,20 @@ public void testFormat() { LayoutFormatter a = new AuthorFirstLastCommas(); // Empty case - Assert.assertEquals("", a.format("")); + assertEquals("", a.format("")); // Single Names - Assert.assertEquals("Van Something Someone", a.format("Someone, Van Something")); + assertEquals("Van Something Someone", a.format("Someone, Van Something")); // Two names - Assert.assertEquals("John von Neumann and Peter Black Brown", a + assertEquals("John von Neumann and Peter Black Brown", a .format("John von Neumann and Peter Black Brown")); // Three names - Assert.assertEquals("John von Neumann, John Smith and Peter Black Brown", a + assertEquals("John von Neumann, John Smith and Peter Black Brown", a .format("von Neumann, John and Smith, John and Black Brown, Peter")); - Assert.assertEquals("John von Neumann, John Smith and Peter Black Brown", a + assertEquals("John von Neumann, John Smith and Peter Black Brown", a .format("John von Neumann and John Smith and Black Brown, Peter")); } diff --git a/src/test/java/org/jabref/logic/layout/format/AuthorFirstLastOxfordCommasTest.java b/src/test/java/org/jabref/logic/layout/format/AuthorFirstLastOxfordCommasTest.java index 736d204cc2b..9f8a91fd569 100644 --- a/src/test/java/org/jabref/logic/layout/format/AuthorFirstLastOxfordCommasTest.java +++ b/src/test/java/org/jabref/logic/layout/format/AuthorFirstLastOxfordCommasTest.java @@ -2,8 +2,8 @@ import org.jabref.logic.layout.LayoutFormatter; -import org.junit.Assert; -import org.junit.Test; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class AuthorFirstLastOxfordCommasTest { @@ -15,20 +15,20 @@ public void testFormat() { LayoutFormatter a = new AuthorFirstLastOxfordCommas(); // Empty case - Assert.assertEquals("", a.format("")); + assertEquals("", a.format("")); // Single Names - Assert.assertEquals("Van Something Someone", a.format("Someone, Van Something")); + assertEquals("Van Something Someone", a.format("Someone, Van Something")); // Two names - Assert.assertEquals("John von Neumann and Peter Black Brown", a + assertEquals("John von Neumann and Peter Black Brown", a .format("John von Neumann and Peter Black Brown")); // Three names - Assert.assertEquals("John von Neumann, John Smith, and Peter Black Brown", a + assertEquals("John von Neumann, John Smith, and Peter Black Brown", a .format("von Neumann, John and Smith, John and Black Brown, Peter")); - Assert.assertEquals("John von Neumann, John Smith, and Peter Black Brown", a + assertEquals("John von Neumann, John Smith, and Peter Black Brown", a .format("John von Neumann and John Smith and Black Brown, Peter")); } diff --git a/src/test/java/org/jabref/logic/layout/format/AuthorLF_FFAbbrTest.java b/src/test/java/org/jabref/logic/layout/format/AuthorLF_FFAbbrTest.java index 65abb81d66c..795c7129f0c 100644 --- a/src/test/java/org/jabref/logic/layout/format/AuthorLF_FFAbbrTest.java +++ b/src/test/java/org/jabref/logic/layout/format/AuthorLF_FFAbbrTest.java @@ -1,7 +1,7 @@ package org.jabref.logic.layout.format; -import org.junit.Assert; -import org.junit.Test; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class AuthorLF_FFAbbrTest { @@ -11,7 +11,7 @@ public class AuthorLF_FFAbbrTest { */ @Test public void testFormat() { - Assert.assertEquals("von Neumann, J. and J. Smith and P. Black Brown, Jr", + assertEquals("von Neumann, J. and J. Smith and P. Black Brown, Jr", new AuthorLF_FFAbbr() .format("von Neumann,,John and John Smith and Black Brown, Jr, Peter")); } diff --git a/src/test/java/org/jabref/logic/layout/format/AuthorLF_FFTest.java b/src/test/java/org/jabref/logic/layout/format/AuthorLF_FFTest.java index 9b07dd6ebe8..1531cbfd0aa 100644 --- a/src/test/java/org/jabref/logic/layout/format/AuthorLF_FFTest.java +++ b/src/test/java/org/jabref/logic/layout/format/AuthorLF_FFTest.java @@ -1,7 +1,7 @@ package org.jabref.logic.layout.format; -import org.junit.Assert; -import org.junit.Test; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class AuthorLF_FFTest { @@ -11,7 +11,7 @@ public class AuthorLF_FFTest { */ @Test public void testFormat() { - Assert.assertEquals("von Neumann, John and John Smith and Peter Black Brown, Jr", + assertEquals("von Neumann, John and John Smith and Peter Black Brown, Jr", new AuthorLF_FF() .format("von Neumann,,John and John Smith and Black Brown, Jr, Peter")); } diff --git a/src/test/java/org/jabref/logic/layout/format/AuthorLastFirstAbbrCommasTest.java b/src/test/java/org/jabref/logic/layout/format/AuthorLastFirstAbbrCommasTest.java index 24ffd914b5a..63faf76cd37 100644 --- a/src/test/java/org/jabref/logic/layout/format/AuthorLastFirstAbbrCommasTest.java +++ b/src/test/java/org/jabref/logic/layout/format/AuthorLastFirstAbbrCommasTest.java @@ -2,8 +2,8 @@ import org.jabref.logic.layout.LayoutFormatter; -import org.junit.Assert; -import org.junit.Test; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class AuthorLastFirstAbbrCommasTest { @@ -15,20 +15,20 @@ public void testFormat() { LayoutFormatter a = new AuthorLastFirstAbbrCommas(); // Empty case - Assert.assertEquals("", a.format("")); + assertEquals("", a.format("")); // Single Names - Assert.assertEquals("Someone, V. S.", a.format("Van Something Someone")); + assertEquals("Someone, V. S.", a.format("Van Something Someone")); // Two names - Assert.assertEquals("von Neumann, J. and Black Brown, P.", a + assertEquals("von Neumann, J. and Black Brown, P.", a .format("John von Neumann and Black Brown, Peter")); // Three names - Assert.assertEquals("von Neumann, J., Smith, J. and Black Brown, P.", a + assertEquals("von Neumann, J., Smith, J. and Black Brown, P.", a .format("von Neumann, John and Smith, John and Black Brown, Peter")); - Assert.assertEquals("von Neumann, J., Smith, J. and Black Brown, P.", a + assertEquals("von Neumann, J., Smith, J. and Black Brown, P.", a .format("John von Neumann and John Smith and Black Brown, Peter")); } diff --git a/src/test/java/org/jabref/logic/layout/format/AuthorLastFirstAbbrOxfordCommasTest.java b/src/test/java/org/jabref/logic/layout/format/AuthorLastFirstAbbrOxfordCommasTest.java index 444bd84e369..e3ada4bd62a 100644 --- a/src/test/java/org/jabref/logic/layout/format/AuthorLastFirstAbbrOxfordCommasTest.java +++ b/src/test/java/org/jabref/logic/layout/format/AuthorLastFirstAbbrOxfordCommasTest.java @@ -2,8 +2,8 @@ import org.jabref.logic.layout.LayoutFormatter; -import org.junit.Assert; -import org.junit.Test; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class AuthorLastFirstAbbrOxfordCommasTest { @@ -15,20 +15,20 @@ public void testFormat() { LayoutFormatter a = new AuthorLastFirstAbbrOxfordCommas(); // Empty case - Assert.assertEquals("", a.format("")); + assertEquals("", a.format("")); // Single Names - Assert.assertEquals("Someone, V. S.", a.format("Van Something Someone")); + assertEquals("Someone, V. S.", a.format("Van Something Someone")); // Two names - Assert.assertEquals("von Neumann, J. and Black Brown, P.", a + assertEquals("von Neumann, J. and Black Brown, P.", a .format("John von Neumann and Black Brown, Peter")); // Three names - Assert.assertEquals("von Neumann, J., Smith, J., and Black Brown, P.", a + assertEquals("von Neumann, J., Smith, J., and Black Brown, P.", a .format("von Neumann, John and Smith, John and Black Brown, Peter")); - Assert.assertEquals("von Neumann, J., Smith, J., and Black Brown, P.", a + assertEquals("von Neumann, J., Smith, J., and Black Brown, P.", a .format("John von Neumann and John Smith and Black Brown, Peter")); } diff --git a/src/test/java/org/jabref/logic/layout/format/AuthorLastFirstAbbreviatorTester.java b/src/test/java/org/jabref/logic/layout/format/AuthorLastFirstAbbreviatorTester.java index a8816d8d10b..8330a62c572 100644 --- a/src/test/java/org/jabref/logic/layout/format/AuthorLastFirstAbbreviatorTester.java +++ b/src/test/java/org/jabref/logic/layout/format/AuthorLastFirstAbbreviatorTester.java @@ -1,7 +1,7 @@ package org.jabref.logic.layout.format; -import org.junit.Assert; -import org.junit.Test; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; /** * Test case that verifies the functionalities of the @@ -19,7 +19,7 @@ public class AuthorLastFirstAbbreviatorTester { */ @Test public void testOneAuthorSimpleName() { - Assert.assertEquals("Abbreviator Test", "Lastname, N.", abbreviate("Lastname, Name")); + assertEquals("Abbreviator Test", "Lastname, N.", abbreviate("Lastname, Name")); } /** @@ -29,7 +29,7 @@ public void testOneAuthorSimpleName() { */ @Test public void testOneAuthorCommonName() { - Assert.assertEquals("Abbreviator Test", "Lastname, N. M.", abbreviate("Lastname, Name Middlename")); + assertEquals("Abbreviator Test", "Lastname, N. M.", abbreviate("Lastname, Name Middlename")); } /** @@ -42,20 +42,20 @@ public void testTwoAuthorsCommonName() { String result = abbreviate("Lastname, Name Middlename and Sobrenome, Nome Nomedomeio"); String expectedResult = "Lastname, N. M. and Sobrenome, N. N."; - Assert.assertEquals("Abbreviator Test", expectedResult, result); + assertEquals("Abbreviator Test", expectedResult, result); } @Test public void testJrAuthor() { - Assert.assertEquals("Other, Jr., A. N.", abbreviate("Other, Jr., Anthony N.")); + assertEquals("Other, Jr., A. N.", abbreviate("Other, Jr., Anthony N.")); } @Test public void testFormat() { - Assert.assertEquals("", abbreviate("")); - Assert.assertEquals("Someone, V. S.", abbreviate("Someone, Van Something")); - Assert.assertEquals("Smith, J.", abbreviate("Smith, John")); - Assert.assertEquals("von Neumann, J. and Smith, J. and Black Brown, P.", + assertEquals("", abbreviate("")); + assertEquals("Someone, V. S.", abbreviate("Someone, Van Something")); + assertEquals("Smith, J.", abbreviate("Smith, John")); + assertEquals("von Neumann, J. and Smith, J. and Black Brown, P.", abbreviate("von Neumann, John and Smith, John and Black Brown, Peter")); } diff --git a/src/test/java/org/jabref/logic/layout/format/AuthorLastFirstCommasTest.java b/src/test/java/org/jabref/logic/layout/format/AuthorLastFirstCommasTest.java index 577f89989f9..9e141ca1925 100644 --- a/src/test/java/org/jabref/logic/layout/format/AuthorLastFirstCommasTest.java +++ b/src/test/java/org/jabref/logic/layout/format/AuthorLastFirstCommasTest.java @@ -2,8 +2,8 @@ import org.jabref.logic.layout.LayoutFormatter; -import org.junit.Assert; -import org.junit.Test; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class AuthorLastFirstCommasTest { @@ -17,20 +17,20 @@ public void testFormat() { LayoutFormatter a = new AuthorLastFirstCommas(); // Empty case - Assert.assertEquals("", a.format("")); + assertEquals("", a.format("")); // Single Names - Assert.assertEquals("Someone, Van Something", a.format("Van Something Someone")); + assertEquals("Someone, Van Something", a.format("Van Something Someone")); // Two names - Assert.assertEquals("von Neumann, John and Black Brown, Peter", a + assertEquals("von Neumann, John and Black Brown, Peter", a .format("John von Neumann and Black Brown, Peter")); // Three names - Assert.assertEquals("von Neumann, John, Smith, John and Black Brown, Peter", a + assertEquals("von Neumann, John, Smith, John and Black Brown, Peter", a .format("von Neumann, John and Smith, John and Black Brown, Peter")); - Assert.assertEquals("von Neumann, John, Smith, John and Black Brown, Peter", a + assertEquals("von Neumann, John, Smith, John and Black Brown, Peter", a .format("John von Neumann and John Smith and Black Brown, Peter")); } diff --git a/src/test/java/org/jabref/logic/layout/format/AuthorLastFirstOxfordCommasTest.java b/src/test/java/org/jabref/logic/layout/format/AuthorLastFirstOxfordCommasTest.java index b25061a5ee4..930a0ae6a6d 100644 --- a/src/test/java/org/jabref/logic/layout/format/AuthorLastFirstOxfordCommasTest.java +++ b/src/test/java/org/jabref/logic/layout/format/AuthorLastFirstOxfordCommasTest.java @@ -2,8 +2,8 @@ import org.jabref.logic.layout.LayoutFormatter; -import org.junit.Assert; -import org.junit.Test; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class AuthorLastFirstOxfordCommasTest { @@ -15,20 +15,20 @@ public void testFormat() { LayoutFormatter a = new AuthorLastFirstOxfordCommas(); // Empty case - Assert.assertEquals("", a.format("")); + assertEquals("", a.format("")); // Single Names - Assert.assertEquals("Someone, Van Something", a.format("Van Something Someone")); + assertEquals("Someone, Van Something", a.format("Van Something Someone")); // Two names - Assert.assertEquals("von Neumann, John and Black Brown, Peter", a + assertEquals("von Neumann, John and Black Brown, Peter", a .format("John von Neumann and Black Brown, Peter")); // Three names - Assert.assertEquals("von Neumann, John, Smith, John, and Black Brown, Peter", a + assertEquals("von Neumann, John, Smith, John, and Black Brown, Peter", a .format("von Neumann, John and Smith, John and Black Brown, Peter")); - Assert.assertEquals("von Neumann, John, Smith, John, and Black Brown, Peter", a + assertEquals("von Neumann, John, Smith, John, and Black Brown, Peter", a .format("John von Neumann and John Smith and Black Brown, Peter")); } diff --git a/src/test/java/org/jabref/logic/layout/format/AuthorLastFirstTest.java b/src/test/java/org/jabref/logic/layout/format/AuthorLastFirstTest.java index e071f7a7844..8d1822ec1b7 100644 --- a/src/test/java/org/jabref/logic/layout/format/AuthorLastFirstTest.java +++ b/src/test/java/org/jabref/logic/layout/format/AuthorLastFirstTest.java @@ -2,8 +2,8 @@ import org.jabref.logic.layout.LayoutFormatter; -import org.junit.Assert; -import org.junit.Test; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class AuthorLastFirstTest { @@ -12,20 +12,20 @@ public void testFormat() { LayoutFormatter a = new AuthorLastFirst(); // Empty case - Assert.assertEquals("", a.format("")); + assertEquals("", a.format("")); // Single Names - Assert.assertEquals("Someone, Van Something", a.format("Van Something Someone")); + assertEquals("Someone, Van Something", a.format("Van Something Someone")); // Two names - Assert.assertEquals("von Neumann, John and Black Brown, Peter", a + assertEquals("von Neumann, John and Black Brown, Peter", a .format("John von Neumann and Black Brown, Peter")); // Three names - Assert.assertEquals("von Neumann, John and Smith, John and Black Brown, Peter", a + assertEquals("von Neumann, John and Smith, John and Black Brown, Peter", a .format("von Neumann, John and Smith, John and Black Brown, Peter")); - Assert.assertEquals("von Neumann, John and Smith, John and Black Brown, Peter", a + assertEquals("von Neumann, John and Smith, John and Black Brown, Peter", a .format("John von Neumann and John Smith and Black Brown, Peter")); } diff --git a/src/test/java/org/jabref/logic/layout/format/AuthorNatBibTest.java b/src/test/java/org/jabref/logic/layout/format/AuthorNatBibTest.java index f1a1de29def..b6308e0daa9 100644 --- a/src/test/java/org/jabref/logic/layout/format/AuthorNatBibTest.java +++ b/src/test/java/org/jabref/logic/layout/format/AuthorNatBibTest.java @@ -1,7 +1,7 @@ package org.jabref.logic.layout.format; -import org.junit.Assert; -import org.junit.Test; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class AuthorNatBibTest { @@ -11,7 +11,7 @@ public class AuthorNatBibTest { */ @Test public void testFormatThreeAuthors() { - Assert.assertEquals("von Neumann et al.", + assertEquals("von Neumann et al.", new AuthorNatBib().format("von Neumann,,John and John Smith and Black Brown, Jr, Peter")); } @@ -21,7 +21,7 @@ public void testFormatThreeAuthors() { */ @Test public void testFormatTwoAuthors() { - Assert.assertEquals("von Neumann and Smith", new AuthorNatBib().format("von Neumann,,John and John Smith")); + assertEquals("von Neumann and Smith", new AuthorNatBib().format("von Neumann,,John and John Smith")); } } diff --git a/src/test/java/org/jabref/logic/layout/format/AuthorOrgSciTest.java b/src/test/java/org/jabref/logic/layout/format/AuthorOrgSciTest.java index 6a67d6f3626..568cae4a8d3 100644 --- a/src/test/java/org/jabref/logic/layout/format/AuthorOrgSciTest.java +++ b/src/test/java/org/jabref/logic/layout/format/AuthorOrgSciTest.java @@ -2,8 +2,8 @@ import org.jabref.logic.layout.LayoutFormatter; -import org.junit.Assert; -import org.junit.Test; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class AuthorOrgSciTest { @@ -11,17 +11,17 @@ public class AuthorOrgSciTest { public void testOrgSci() { LayoutFormatter f = new AuthorOrgSci(); - Assert.assertEquals("Flynn, J., S. Gartska", f.format("John Flynn and Sabine Gartska")); - Assert.assertEquals("Garvin, D. A.", f.format("David A. Garvin")); - Assert.assertEquals("Makridakis, S., S. C. Wheelwright, V. E. McGee", f.format("Sa Makridakis and Sa Ca Wheelwright and Va Ea McGee")); + assertEquals("Flynn, J., S. Gartska", f.format("John Flynn and Sabine Gartska")); + assertEquals("Garvin, D. A.", f.format("David A. Garvin")); + assertEquals("Makridakis, S., S. C. Wheelwright, V. E. McGee", f.format("Sa Makridakis and Sa Ca Wheelwright and Va Ea McGee")); } @Test public void testOrgSciPlusAbbreviation() { LayoutFormatter f = new CompositeFormat(new AuthorOrgSci(), new NoSpaceBetweenAbbreviations()); - Assert.assertEquals("Flynn, J., S. Gartska", f.format("John Flynn and Sabine Gartska")); - Assert.assertEquals("Garvin, D.A.", f.format("David A. Garvin")); - Assert.assertEquals("Makridakis, S., S.C. Wheelwright, V.E. McGee", f.format("Sa Makridakis and Sa Ca Wheelwright and Va Ea McGee")); + assertEquals("Flynn, J., S. Gartska", f.format("John Flynn and Sabine Gartska")); + assertEquals("Garvin, D.A.", f.format("David A. Garvin")); + assertEquals("Makridakis, S., S.C. Wheelwright, V.E. McGee", f.format("Sa Makridakis and Sa Ca Wheelwright and Va Ea McGee")); } } diff --git a/src/test/java/org/jabref/logic/layout/format/AuthorsTest.java b/src/test/java/org/jabref/logic/layout/format/AuthorsTest.java index 053d2742159..581d32c236f 100644 --- a/src/test/java/org/jabref/logic/layout/format/AuthorsTest.java +++ b/src/test/java/org/jabref/logic/layout/format/AuthorsTest.java @@ -2,15 +2,15 @@ import org.jabref.logic.layout.ParamLayoutFormatter; -import org.junit.Assert; -import org.junit.Test; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class AuthorsTest { @Test public void testStandardUsage() { ParamLayoutFormatter a = new Authors(); - Assert.assertEquals("B. C. Bruce, C. Manson and J. Jumper", + assertEquals("B. C. Bruce, C. Manson and J. Jumper", a.format("Bob Croydon Bruce and Charles Manson and Jolly Jumper")); } @@ -18,21 +18,21 @@ public void testStandardUsage() { public void testStandardUsageOne() { ParamLayoutFormatter a = new Authors(); a.setArgument("fullname, LastFirst, Comma, Comma"); - Assert.assertEquals("Bruce, Bob Croydon, Jumper, Jolly", a.format("Bob Croydon Bruce and Jolly Jumper")); + assertEquals("Bruce, Bob Croydon, Jumper, Jolly", a.format("Bob Croydon Bruce and Jolly Jumper")); } @Test public void testStandardUsageTwo() { ParamLayoutFormatter a = new Authors(); a.setArgument("initials"); - Assert.assertEquals("B. C. Bruce and J. Jumper", a.format("Bob Croydon Bruce and Jolly Jumper")); + assertEquals("B. C. Bruce and J. Jumper", a.format("Bob Croydon Bruce and Jolly Jumper")); } @Test public void testStandardUsageThree() { ParamLayoutFormatter a = new Authors(); a.setArgument("fullname, LastFirst, Comma"); - Assert.assertEquals("Bruce, Bob Croydon, Manson, Charles and Jumper, Jolly", + assertEquals("Bruce, Bob Croydon, Manson, Charles and Jumper, Jolly", a.format("Bob Croydon Bruce and Charles Manson and Jolly Jumper")); } @@ -40,7 +40,7 @@ public void testStandardUsageThree() { public void testStandardUsageFour() { ParamLayoutFormatter a = new Authors(); a.setArgument("fullname, LastFirst, Comma, 2"); - Assert.assertEquals("Bruce, Bob Croydon et al.", + assertEquals("Bruce, Bob Croydon et al.", a.format("Bob Croydon Bruce and Charles Manson and Jolly Jumper")); } @@ -48,7 +48,7 @@ public void testStandardUsageFour() { public void testStandardUsageFive() { ParamLayoutFormatter a = new Authors(); a.setArgument("fullname, LastFirst, Comma, 3"); - Assert.assertEquals("Bruce, Bob Croydon et al.", + assertEquals("Bruce, Bob Croydon et al.", a.format("Bob Croydon Bruce and Charles Manson and Jolly Jumper and Chuck Chuckles")); } @@ -56,7 +56,7 @@ public void testStandardUsageFive() { public void testStandardUsageSix() { ParamLayoutFormatter a = new Authors(); a.setArgument("fullname, LastFirst, Comma, 3, 2"); - Assert.assertEquals("Bruce, Bob Croydon, Manson, Charles et al.", + assertEquals("Bruce, Bob Croydon, Manson, Charles et al.", a.format("Bob Croydon Bruce and Charles Manson and Jolly Jumper and Chuck Chuckles")); } @@ -64,21 +64,21 @@ public void testStandardUsageSix() { public void testSpecialEtAl() { ParamLayoutFormatter a = new Authors(); a.setArgument("fullname, LastFirst, Comma, 3, etal= and a few more"); - Assert.assertEquals("Bruce, Bob Croydon and a few more", + assertEquals("Bruce, Bob Croydon and a few more", a.format("Bob Croydon Bruce and Charles Manson and Jolly Jumper and Chuck Chuckles")); } @Test public void testStandardUsageNull() { ParamLayoutFormatter a = new Authors(); - Assert.assertEquals("", a.format(null)); + assertEquals("", a.format(null)); } @Test public void testStandardOxford() { ParamLayoutFormatter a = new Authors(); a.setArgument("Oxford"); - Assert.assertEquals("B. C. Bruce, C. Manson, and J. Jumper", + assertEquals("B. C. Bruce, C. Manson, and J. Jumper", a.format("Bob Croydon Bruce and Charles Manson and Jolly Jumper")); } @@ -86,7 +86,7 @@ public void testStandardOxford() { public void testStandardOxfordFullName() { ParamLayoutFormatter a = new Authors(); a.setArgument("FullName,Oxford"); - Assert.assertEquals("Bob Croydon Bruce, Charles Manson, and Jolly Jumper", + assertEquals("Bob Croydon Bruce, Charles Manson, and Jolly Jumper", a.format("Bruce, Bob Croydon and Charles Manson and Jolly Jumper")); } @@ -94,7 +94,7 @@ public void testStandardOxfordFullName() { public void testStandardCommaFullName() { ParamLayoutFormatter a = new Authors(); a.setArgument("FullName,Comma,Comma"); - Assert.assertEquals("Bob Croydon Bruce, Charles Manson, Jolly Jumper", + assertEquals("Bob Croydon Bruce, Charles Manson, Jolly Jumper", a.format("Bruce, Bob Croydon and Charles Manson and Jolly Jumper")); } @@ -102,7 +102,7 @@ public void testStandardCommaFullName() { public void testStandardAmpFullName() { ParamLayoutFormatter a = new Authors(); a.setArgument("FullName,Amp"); - Assert.assertEquals("Bob Croydon Bruce, Charles Manson & Jolly Jumper", + assertEquals("Bob Croydon Bruce, Charles Manson & Jolly Jumper", a.format("Bruce, Bob Croydon and Charles Manson and Jolly Jumper")); } @@ -110,7 +110,7 @@ public void testStandardAmpFullName() { public void testLastName() { ParamLayoutFormatter a = new Authors(); a.setArgument("LastName"); - Assert.assertEquals("Bruce, von Manson and Jumper", + assertEquals("Bruce, von Manson and Jumper", a.format("Bruce, Bob Croydon and Charles von Manson and Jolly Jumper")); } @@ -118,7 +118,7 @@ public void testLastName() { public void testMiddleInitial() { ParamLayoutFormatter a = new Authors(); a.setArgument("MiddleInitial"); - Assert.assertEquals("Bob C. Bruce, Charles K. von Manson and Jolly Jumper", + assertEquals("Bob C. Bruce, Charles K. von Manson and Jolly Jumper", a.format("Bruce, Bob Croydon and Charles Kermit von Manson and Jumper, Jolly")); } @@ -126,7 +126,7 @@ public void testMiddleInitial() { public void testNoPeriod() { ParamLayoutFormatter a = new Authors(); a.setArgument("NoPeriod"); - Assert.assertEquals("B C Bruce, C K von Manson and J Jumper", + assertEquals("B C Bruce, C K von Manson and J Jumper", a.format("Bruce, Bob Croydon and Charles Kermit von Manson and Jumper, Jolly")); } @@ -134,7 +134,7 @@ public void testNoPeriod() { public void testEtAl() { ParamLayoutFormatter a = new Authors(); a.setArgument("2,1"); - Assert.assertEquals("B. C. Bruce et al.", + assertEquals("B. C. Bruce et al.", a.format("Bruce, Bob Croydon and Charles Kermit von Manson and Jumper, Jolly")); } @@ -142,7 +142,7 @@ public void testEtAl() { public void testEtAlNotEnoughAuthors() { ParamLayoutFormatter a = new Authors(); a.setArgument("2,1"); - Assert.assertEquals("B. C. Bruce and C. K. von Manson", + assertEquals("B. C. Bruce and C. K. von Manson", a.format("Bruce, Bob Croydon and Charles Kermit von Manson")); } @@ -150,7 +150,7 @@ public void testEtAlNotEnoughAuthors() { public void testEmptyEtAl() { ParamLayoutFormatter a = new Authors(); a.setArgument("fullname, LastFirst, Comma, 3, etal="); - Assert.assertEquals("Bruce, Bob Croydon", + assertEquals("Bruce, Bob Croydon", a.format("Bob Croydon Bruce and Charles Manson and Jolly Jumper and Chuck Chuckles")); } diff --git a/src/test/java/org/jabref/logic/layout/format/CompositeFormatTest.java b/src/test/java/org/jabref/logic/layout/format/CompositeFormatTest.java index c86dedaf2c5..b7869a703ff 100644 --- a/src/test/java/org/jabref/logic/layout/format/CompositeFormatTest.java +++ b/src/test/java/org/jabref/logic/layout/format/CompositeFormatTest.java @@ -2,15 +2,15 @@ import org.jabref.logic.layout.LayoutFormatter; -import org.junit.Assert; -import org.junit.Test; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class CompositeFormatTest { @Test public void testEmptyComposite() { LayoutFormatter f = new CompositeFormat(); - Assert.assertEquals("No Change", f.format("No Change")); + assertEquals("No Change", f.format("No Change")); } @Test @@ -18,7 +18,7 @@ public void testArrayComposite() { LayoutFormatter f = new CompositeFormat(new LayoutFormatter[] {fieldText -> fieldText + fieldText, fieldText -> "A" + fieldText, fieldText -> "B" + fieldText}); - Assert.assertEquals("BAff", f.format("f")); + assertEquals("BAff", f.format("f")); } @Test @@ -28,9 +28,9 @@ public void testDoubleComposite() { LayoutFormatter first = new AuthorOrgSci(); LayoutFormatter second = new NoSpaceBetweenAbbreviations(); - Assert.assertEquals(second.format(first.format("John Flynn and Sabine Gartska")), + assertEquals(second.format(first.format("John Flynn and Sabine Gartska")), f.format("John Flynn and Sabine Gartska")); - Assert.assertEquals(second.format(first.format("Sa Makridakis and Sa Ca Wheelwright and Va Ea McGee")), + assertEquals(second.format(first.format("Sa Makridakis and Sa Ca Wheelwright and Va Ea McGee")), f.format("Sa Makridakis and Sa Ca Wheelwright and Va Ea McGee")); } diff --git a/src/test/java/org/jabref/logic/layout/format/DOICheckTest.java b/src/test/java/org/jabref/logic/layout/format/DOICheckTest.java index b8d5a8f2d5f..fae8c751630 100644 --- a/src/test/java/org/jabref/logic/layout/format/DOICheckTest.java +++ b/src/test/java/org/jabref/logic/layout/format/DOICheckTest.java @@ -2,8 +2,8 @@ import org.jabref.logic.layout.LayoutFormatter; -import org.junit.Assert; -import org.junit.Test; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class DOICheckTest { @@ -11,28 +11,28 @@ public class DOICheckTest { public void testFormat() { LayoutFormatter lf = new DOICheck(); - Assert.assertEquals("", lf.format("")); - Assert.assertEquals(null, lf.format(null)); + assertEquals("", lf.format("")); + assertEquals(null, lf.format(null)); - Assert.assertEquals("https://doi.org/10.1000/ISBN1-900512-44-0", lf.format("10.1000/ISBN1-900512-44-0")); - Assert.assertEquals("https://doi.org/10.1000/ISBN1-900512-44-0", + assertEquals("https://doi.org/10.1000/ISBN1-900512-44-0", lf.format("10.1000/ISBN1-900512-44-0")); + assertEquals("https://doi.org/10.1000/ISBN1-900512-44-0", lf.format("http://dx.doi.org/10.1000/ISBN1-900512-44-0")); - Assert.assertEquals("https://doi.org/10.1000/ISBN1-900512-44-0", + assertEquals("https://doi.org/10.1000/ISBN1-900512-44-0", lf.format("http://doi.acm.org/10.1000/ISBN1-900512-44-0")); - Assert.assertEquals("https://doi.org/10.1145/354401.354407", + assertEquals("https://doi.org/10.1145/354401.354407", lf.format("http://doi.acm.org/10.1145/354401.354407")); - Assert.assertEquals("https://doi.org/10.1145/354401.354407", lf.format("10.1145/354401.354407")); + assertEquals("https://doi.org/10.1145/354401.354407", lf.format("10.1145/354401.354407")); // Works even when having a / at the front - Assert.assertEquals("https://doi.org/10.1145/354401.354407", lf.format("/10.1145/354401.354407")); + assertEquals("https://doi.org/10.1145/354401.354407", lf.format("/10.1145/354401.354407")); // Obviously a wrong doi, will not change anything. - Assert.assertEquals("10", lf.format("10")); + assertEquals("10", lf.format("10")); // Obviously a wrong doi, will not change anything. - Assert.assertEquals("1", lf.format("1")); + assertEquals("1", lf.format("1")); } } diff --git a/src/test/java/org/jabref/logic/layout/format/DOIStripTest.java b/src/test/java/org/jabref/logic/layout/format/DOIStripTest.java index caf97829225..c4f40d3b835 100644 --- a/src/test/java/org/jabref/logic/layout/format/DOIStripTest.java +++ b/src/test/java/org/jabref/logic/layout/format/DOIStripTest.java @@ -2,8 +2,8 @@ import org.jabref.logic.layout.LayoutFormatter; -import org.junit.Assert; -import org.junit.Test; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class DOIStripTest { @@ -11,14 +11,14 @@ public class DOIStripTest { public void testFormat() { LayoutFormatter lf = new DOIStrip(); - Assert.assertEquals("", lf.format("")); - Assert.assertEquals(null, lf.format(null)); + assertEquals("", lf.format("")); + assertEquals(null, lf.format(null)); - Assert.assertEquals("10.1000/ISBN1-900512-44-0", lf.format("10.1000/ISBN1-900512-44-0")); - Assert.assertEquals("10.1000/ISBN1-900512-44-0", + assertEquals("10.1000/ISBN1-900512-44-0", lf.format("10.1000/ISBN1-900512-44-0")); + assertEquals("10.1000/ISBN1-900512-44-0", lf.format("http://dx.doi.org/10.1000/ISBN1-900512-44-0")); - Assert.assertEquals("10.1000/ISBN1-900512-44-0", + assertEquals("10.1000/ISBN1-900512-44-0", lf.format("http://doi.acm.org/10.1000/ISBN1-900512-44-0")); } diff --git a/src/test/java/org/jabref/logic/layout/format/DateFormatterTest.java b/src/test/java/org/jabref/logic/layout/format/DateFormatterTest.java index 6ab23b675da..7ada16578a6 100644 --- a/src/test/java/org/jabref/logic/layout/format/DateFormatterTest.java +++ b/src/test/java/org/jabref/logic/layout/format/DateFormatterTest.java @@ -2,28 +2,28 @@ import org.jabref.logic.layout.ParamLayoutFormatter; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class DateFormatterTest { private ParamLayoutFormatter formatter; - @Before + @BeforeEach public void setUp() { formatter = new DateFormatter(); } @Test public void testDefaultFormat() { - Assert.assertEquals("2016-07-15", formatter.format("2016-07-15")); + assertEquals("2016-07-15", formatter.format("2016-07-15")); } @Test public void testRequestedFormat() { formatter.setArgument("MM/yyyy"); - Assert.assertEquals("07/2016", formatter.format("2016-07-15")); + assertEquals("07/2016", formatter.format("2016-07-15")); } } diff --git a/src/test/java/org/jabref/logic/layout/format/DefaultTest.java b/src/test/java/org/jabref/logic/layout/format/DefaultTest.java index 6a90b3a3f92..c4c386d2975 100644 --- a/src/test/java/org/jabref/logic/layout/format/DefaultTest.java +++ b/src/test/java/org/jabref/logic/layout/format/DefaultTest.java @@ -2,8 +2,8 @@ import org.jabref.logic.layout.ParamLayoutFormatter; -import org.junit.Assert; -import org.junit.Test; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class DefaultTest { @@ -11,39 +11,39 @@ public class DefaultTest { public void testSimpleText() { ParamLayoutFormatter a = new Default(); a.setArgument("DEFAULT TEXT"); - Assert.assertEquals("Bob Bruce", a.format("Bob Bruce")); + assertEquals("Bob Bruce", a.format("Bob Bruce")); } @Test public void testFormatNullExpectReplace() { ParamLayoutFormatter a = new Default(); a.setArgument("DEFAULT TEXT"); - Assert.assertEquals("DEFAULT TEXT", a.format(null)); + assertEquals("DEFAULT TEXT", a.format(null)); } @Test public void testFormatEmpty() { ParamLayoutFormatter a = new Default(); a.setArgument("DEFAULT TEXT"); - Assert.assertEquals("DEFAULT TEXT", a.format("")); + assertEquals("DEFAULT TEXT", a.format("")); } @Test public void testNoArgumentSet() { ParamLayoutFormatter a = new Default(); - Assert.assertEquals("Bob Bruce and Jolly Jumper", a.format("Bob Bruce and Jolly Jumper")); + assertEquals("Bob Bruce and Jolly Jumper", a.format("Bob Bruce and Jolly Jumper")); } @Test public void testNoArgumentSetNullInput() { ParamLayoutFormatter a = new Default(); - Assert.assertEquals("", a.format(null)); + assertEquals("", a.format(null)); } @Test public void testNoArgumentSetEmptyInput() { ParamLayoutFormatter a = new Default(); - Assert.assertEquals("", a.format("")); + assertEquals("", a.format("")); } } diff --git a/src/test/java/org/jabref/logic/layout/format/EntryTypeFormatterTest.java b/src/test/java/org/jabref/logic/layout/format/EntryTypeFormatterTest.java index 453278465f2..89d6850f593 100644 --- a/src/test/java/org/jabref/logic/layout/format/EntryTypeFormatterTest.java +++ b/src/test/java/org/jabref/logic/layout/format/EntryTypeFormatterTest.java @@ -1,16 +1,16 @@ package org.jabref.logic.layout.format; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class EntryTypeFormatterTest { private EntryTypeFormatter formatter; - @Before + @BeforeEach public void setUp() { formatter = new EntryTypeFormatter(); } diff --git a/src/test/java/org/jabref/logic/layout/format/FileLinkTest.java b/src/test/java/org/jabref/logic/layout/format/FileLinkTest.java index 4876f79c20b..23c5c205232 100644 --- a/src/test/java/org/jabref/logic/layout/format/FileLinkTest.java +++ b/src/test/java/org/jabref/logic/layout/format/FileLinkTest.java @@ -2,17 +2,17 @@ import org.jabref.logic.layout.ParamLayoutFormatter; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.mock; public class FileLinkTest { private FileLinkPreferences prefs; - @Before + @BeforeEach public void setUp() throws Exception { prefs = mock(FileLinkPreferences.class); } diff --git a/src/test/java/org/jabref/logic/layout/format/FirstPageTest.java b/src/test/java/org/jabref/logic/layout/format/FirstPageTest.java index f8809ed1b8c..5c20c5d7898 100644 --- a/src/test/java/org/jabref/logic/layout/format/FirstPageTest.java +++ b/src/test/java/org/jabref/logic/layout/format/FirstPageTest.java @@ -2,38 +2,38 @@ import org.jabref.logic.layout.LayoutFormatter; -import org.junit.Assert; -import org.junit.Test; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class FirstPageTest { @Test public void testFormatEmpty() { LayoutFormatter a = new FirstPage(); - Assert.assertEquals("", a.format("")); + assertEquals("", a.format("")); } @Test public void testFormatNull() { LayoutFormatter a = new FirstPage(); - Assert.assertEquals("", a.format(null)); + assertEquals("", a.format(null)); } @Test public void testFormatSinglePage() { LayoutFormatter a = new FirstPage(); - Assert.assertEquals("345", a.format("345")); + assertEquals("345", a.format("345")); } @Test public void testFormatSingleDash() { LayoutFormatter a = new FirstPage(); - Assert.assertEquals("345", a.format("345-350")); + assertEquals("345", a.format("345-350")); } @Test public void testFormatDoubleDash() { LayoutFormatter a = new FirstPage(); - Assert.assertEquals("345", a.format("345--350")); + assertEquals("345", a.format("345--350")); } } diff --git a/src/test/java/org/jabref/logic/layout/format/HTMLCharsTest.java b/src/test/java/org/jabref/logic/layout/format/HTMLCharsTest.java index 18a32ed6168..42d6a488683 100644 --- a/src/test/java/org/jabref/logic/layout/format/HTMLCharsTest.java +++ b/src/test/java/org/jabref/logic/layout/format/HTMLCharsTest.java @@ -2,16 +2,16 @@ import org.jabref.logic.layout.LayoutFormatter; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class HTMLCharsTest { private LayoutFormatter layout; - @Before + @BeforeEach public void setUp() { layout = new HTMLChars(); } diff --git a/src/test/java/org/jabref/logic/layout/format/HTMLParagraphsTest.java b/src/test/java/org/jabref/logic/layout/format/HTMLParagraphsTest.java index ee011961aac..6cd36359c4e 100644 --- a/src/test/java/org/jabref/logic/layout/format/HTMLParagraphsTest.java +++ b/src/test/java/org/jabref/logic/layout/format/HTMLParagraphsTest.java @@ -2,8 +2,8 @@ import org.jabref.logic.layout.LayoutFormatter; -import org.junit.Assert; -import org.junit.Test; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class HTMLParagraphsTest { @@ -12,11 +12,11 @@ public void testFormat() { LayoutFormatter f = new HTMLParagraphs(); - Assert.assertEquals("", f.format("")); - Assert.assertEquals("

\nHello\n

", f.format("Hello")); - Assert.assertEquals("

\nHello\nWorld\n

", f.format("Hello\nWorld")); - Assert.assertEquals("

\nHello World\n

\n

\nWhat a lovely day\n

", f.format("Hello World\n \nWhat a lovely day\n")); - Assert.assertEquals("

\nHello World\n

\n

\nCould not be any better\n

\n

\nWhat a lovely day\n

", f.format("Hello World\n \n\nCould not be any better\n\nWhat a lovely day\n")); + assertEquals("", f.format("")); + assertEquals("

\nHello\n

", f.format("Hello")); + assertEquals("

\nHello\nWorld\n

", f.format("Hello\nWorld")); + assertEquals("

\nHello World\n

\n

\nWhat a lovely day\n

", f.format("Hello World\n \nWhat a lovely day\n")); + assertEquals("

\nHello World\n

\n

\nCould not be any better\n

\n

\nWhat a lovely day\n

", f.format("Hello World\n \n\nCould not be any better\n\nWhat a lovely day\n")); } diff --git a/src/test/java/org/jabref/logic/layout/format/IfPluralTest.java b/src/test/java/org/jabref/logic/layout/format/IfPluralTest.java index 26753d0ff8c..5ebd278be81 100644 --- a/src/test/java/org/jabref/logic/layout/format/IfPluralTest.java +++ b/src/test/java/org/jabref/logic/layout/format/IfPluralTest.java @@ -2,8 +2,8 @@ import org.jabref.logic.layout.ParamLayoutFormatter; -import org.junit.Assert; -import org.junit.Test; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class IfPluralTest { @@ -11,40 +11,40 @@ public class IfPluralTest { public void testStandardUsageOneEditor() { ParamLayoutFormatter a = new IfPlural(); a.setArgument("Eds.,Ed."); - Assert.assertEquals("Ed.", a.format("Bob Bruce")); + assertEquals("Ed.", a.format("Bob Bruce")); } @Test public void testStandardUsageTwoEditors() { ParamLayoutFormatter a = new IfPlural(); a.setArgument("Eds.,Ed."); - Assert.assertEquals("Eds.", a.format("Bob Bruce and Jolly Jumper")); + assertEquals("Eds.", a.format("Bob Bruce and Jolly Jumper")); } @Test public void testFormatNull() { ParamLayoutFormatter a = new IfPlural(); a.setArgument("Eds.,Ed."); - Assert.assertEquals("", a.format(null)); + assertEquals("", a.format(null)); } @Test public void testFormatEmpty() { ParamLayoutFormatter a = new IfPlural(); a.setArgument("Eds.,Ed."); - Assert.assertEquals("", a.format("")); + assertEquals("", a.format("")); } @Test public void testNoArgumentSet() { ParamLayoutFormatter a = new IfPlural(); - Assert.assertEquals("", a.format("Bob Bruce and Jolly Jumper")); + assertEquals("", a.format("Bob Bruce and Jolly Jumper")); } @Test public void testNoProperArgument() { ParamLayoutFormatter a = new IfPlural(); a.setArgument("Eds."); - Assert.assertEquals("", a.format("Bob Bruce and Jolly Jumper")); + assertEquals("", a.format("Bob Bruce and Jolly Jumper")); } } diff --git a/src/test/java/org/jabref/logic/layout/format/LastPageTest.java b/src/test/java/org/jabref/logic/layout/format/LastPageTest.java index 9590d9cd47e..64dece591f0 100644 --- a/src/test/java/org/jabref/logic/layout/format/LastPageTest.java +++ b/src/test/java/org/jabref/logic/layout/format/LastPageTest.java @@ -2,44 +2,44 @@ import org.jabref.logic.layout.LayoutFormatter; -import org.junit.Assert; -import org.junit.Test; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class LastPageTest { @Test public void testFormatEmpty() { LayoutFormatter a = new LastPage(); - Assert.assertEquals("", a.format("")); + assertEquals("", a.format("")); } @Test public void testFormatNull() { LayoutFormatter a = new LastPage(); - Assert.assertEquals("", a.format(null)); + assertEquals("", a.format(null)); } @Test public void testFormatSinglePage() { LayoutFormatter a = new LastPage(); - Assert.assertEquals("345", a.format("345")); + assertEquals("345", a.format("345")); } @Test public void testFormatSingleDash() { LayoutFormatter a = new LastPage(); - Assert.assertEquals("350", a.format("345-350")); + assertEquals("350", a.format("345-350")); } @Test public void testFormatDoubleDash() { LayoutFormatter a = new LastPage(); - Assert.assertEquals("350", a.format("345--350")); + assertEquals("350", a.format("345--350")); } @Test public void testFinalCoverageCase() { LayoutFormatter a = new LastPage(); - Assert.assertEquals("", a.format("--")); + assertEquals("", a.format("--")); } } diff --git a/src/test/java/org/jabref/logic/layout/format/LatexToUnicodeFormatterTest.java b/src/test/java/org/jabref/logic/layout/format/LatexToUnicodeFormatterTest.java index bf31aa7c6cc..721c855362e 100644 --- a/src/test/java/org/jabref/logic/layout/format/LatexToUnicodeFormatterTest.java +++ b/src/test/java/org/jabref/logic/layout/format/LatexToUnicodeFormatterTest.java @@ -1,9 +1,9 @@ package org.jabref.logic.layout.format; import org.junit.Ignore; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class LatexToUnicodeFormatterTest { diff --git a/src/test/java/org/jabref/logic/layout/format/NameFormatterTest.java b/src/test/java/org/jabref/logic/layout/format/NameFormatterTest.java index 194226a19f2..0b5adc77462 100644 --- a/src/test/java/org/jabref/logic/layout/format/NameFormatterTest.java +++ b/src/test/java/org/jabref/logic/layout/format/NameFormatterTest.java @@ -1,7 +1,7 @@ package org.jabref.logic.layout.format; -import org.junit.Assert; -import org.junit.Test; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class NameFormatterTest { @@ -10,21 +10,21 @@ public void testFormatStringStringBibtexEntry() { NameFormatter l = new NameFormatter(); - Assert.assertEquals("Doe", l.format("Joe Doe", "1@*@{ll}")); + assertEquals("Doe", l.format("Joe Doe", "1@*@{ll}")); - Assert.assertEquals("moremoremoremore", l.format("Joe Doe and Mary Jane and Bruce Bar and Arthur Kay", + assertEquals("moremoremoremore", l.format("Joe Doe and Mary Jane and Bruce Bar and Arthur Kay", "1@*@{ll}@@2@1..1@{ff}{ll}@2..2@ and {ff}{last}@@*@*@more")); - Assert.assertEquals("Doe", l.format("Joe Doe", "1@*@{ll}@@2@1..1@{ff}{ll}@2..2@ and {ff}{last}@@*@*@more")); + assertEquals("Doe", l.format("Joe Doe", "1@*@{ll}@@2@1..1@{ff}{ll}@2..2@ and {ff}{last}@@*@*@more")); - Assert.assertEquals("JoeDoe and MaryJ", + assertEquals("JoeDoe and MaryJ", l.format("Joe Doe and Mary Jane", "1@*@{ll}@@2@1..1@{ff}{ll}@2..2@ and {ff}{l}@@*@*@more")); - Assert.assertEquals("Doe, Joe and Jane, M. and Kamp, J.~A.", + assertEquals("Doe, Joe and Jane, M. and Kamp, J.~A.", l.format("Joe Doe and Mary Jane and John Arthur van Kamp", "1@*@{ll}, {ff}@@*@1@{ll}, {ff}@2..-1@ and {ll}, {f}.")); - Assert.assertEquals("Doe Joe and Jane, M. and Kamp, J.~A.", + assertEquals("Doe Joe and Jane, M. and Kamp, J.~A.", l.format("Joe Doe and Mary Jane and John Arthur van Kamp", "1@*@{ll}, {ff}@@*@1@{ll} {ff}@2..-1@ and {ll}, {f}.")); @@ -36,26 +36,26 @@ public void testFormat() { NameFormatter a = new NameFormatter(); // Empty case - Assert.assertEquals("", a.format("")); + assertEquals("", a.format("")); String formatString = "1@1@{vv }{ll}{ ff}@@2@1@{vv }{ll}{ ff}@2@ and {vv }{ll}{, ff}@@*@1@{vv }{ll}{ ff}@2..-2@, {vv }{ll}{, ff}@-1@ and {vv }{ll}{, ff}"; // Single Names - Assert.assertEquals("Vandekamp Mary~Ann", a.format("Mary Ann Vandekamp", formatString)); + assertEquals("Vandekamp Mary~Ann", a.format("Mary Ann Vandekamp", formatString)); // Two names - Assert.assertEquals("von Neumann John and Black~Brown, Peter", + assertEquals("von Neumann John and Black~Brown, Peter", a.format("John von Neumann and Black Brown, Peter", formatString)); // Three names - Assert.assertEquals("von Neumann John, Smith, John and Black~Brown, Peter", + assertEquals("von Neumann John, Smith, John and Black~Brown, Peter", a.format("von Neumann, John and Smith, John and Black Brown, Peter", formatString)); - Assert.assertEquals("von Neumann John, Smith, John and Black~Brown, Peter", + assertEquals("von Neumann John, Smith, John and Black~Brown, Peter", a.format("John von Neumann and John Smith and Black Brown, Peter", formatString)); // Four names - Assert.assertEquals("von Neumann John, Smith, John, Vandekamp, Mary~Ann and Black~Brown, Peter", a.format( + assertEquals("von Neumann John, Smith, John, Vandekamp, Mary~Ann and Black~Brown, Peter", a.format( "von Neumann, John and Smith, John and Vandekamp, Mary Ann and Black Brown, Peter", formatString)); } diff --git a/src/test/java/org/jabref/logic/layout/format/NoSpaceBetweenAbbreviationsTest.java b/src/test/java/org/jabref/logic/layout/format/NoSpaceBetweenAbbreviationsTest.java index b79664903d9..e49493fe097 100644 --- a/src/test/java/org/jabref/logic/layout/format/NoSpaceBetweenAbbreviationsTest.java +++ b/src/test/java/org/jabref/logic/layout/format/NoSpaceBetweenAbbreviationsTest.java @@ -2,19 +2,19 @@ import org.jabref.logic.layout.LayoutFormatter; -import org.junit.Assert; -import org.junit.Test; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class NoSpaceBetweenAbbreviationsTest { @Test public void testFormat() { LayoutFormatter f = new NoSpaceBetweenAbbreviations(); - Assert.assertEquals("", f.format("")); - Assert.assertEquals("John Meier", f.format("John Meier")); - Assert.assertEquals("J.F. Kennedy", f.format("J. F. Kennedy")); - Assert.assertEquals("J.R.R. Tolkien", f.format("J. R. R. Tolkien")); - Assert.assertEquals("J.R.R. Tolkien and J.F. Kennedy", f.format("J. R. R. Tolkien and J. F. Kennedy")); + assertEquals("", f.format("")); + assertEquals("John Meier", f.format("John Meier")); + assertEquals("J.F. Kennedy", f.format("J. F. Kennedy")); + assertEquals("J.R.R. Tolkien", f.format("J. R. R. Tolkien")); + assertEquals("J.R.R. Tolkien and J.F. Kennedy", f.format("J. R. R. Tolkien and J. F. Kennedy")); } } diff --git a/src/test/java/org/jabref/logic/layout/format/OrdinalTest.java b/src/test/java/org/jabref/logic/layout/format/OrdinalTest.java index 894e2614859..af73ab217be 100644 --- a/src/test/java/org/jabref/logic/layout/format/OrdinalTest.java +++ b/src/test/java/org/jabref/logic/layout/format/OrdinalTest.java @@ -1,9 +1,9 @@ package org.jabref.logic.layout.format; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; public class OrdinalTest { diff --git a/src/test/java/org/jabref/logic/layout/format/RTFCharsTest.java b/src/test/java/org/jabref/logic/layout/format/RTFCharsTest.java index fc89b7de057..bda54482342 100644 --- a/src/test/java/org/jabref/logic/layout/format/RTFCharsTest.java +++ b/src/test/java/org/jabref/logic/layout/format/RTFCharsTest.java @@ -3,14 +3,14 @@ import org.jabref.logic.layout.LayoutFormatter; import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class RTFCharsTest { private LayoutFormatter formatter; - @Before + @BeforeEach public void setUp() { formatter = new RTFChars(); } @@ -22,44 +22,44 @@ public void tearDown() { @Test public void testBasicFormat() { - Assert.assertEquals("", formatter.format("")); + assertEquals("", formatter.format("")); - Assert.assertEquals("hallo", formatter.format("hallo")); + assertEquals("hallo", formatter.format("hallo")); - Assert.assertEquals("R\\u233eflexions sur le timing de la quantit\\u233e", + assertEquals("R\\u233eflexions sur le timing de la quantit\\u233e", formatter.format("Réflexions sur le timing de la quantité")); - Assert.assertEquals("h\\'e1llo", formatter.format("h\\'allo")); - Assert.assertEquals("h\\'e1llo", formatter.format("h\\'allo")); + assertEquals("h\\'e1llo", formatter.format("h\\'allo")); + assertEquals("h\\'e1llo", formatter.format("h\\'allo")); } @Test public void testLaTeXHighlighting() { - Assert.assertEquals("{\\i hallo}", formatter.format("\\emph{hallo}")); - Assert.assertEquals("{\\i hallo}", formatter.format("{\\emph hallo}")); - Assert.assertEquals("An article title with {\\i a book title} emphasized", formatter.format("An article title with \\emph{a book title} emphasized")); + assertEquals("{\\i hallo}", formatter.format("\\emph{hallo}")); + assertEquals("{\\i hallo}", formatter.format("{\\emph hallo}")); + assertEquals("An article title with {\\i a book title} emphasized", formatter.format("An article title with \\emph{a book title} emphasized")); - Assert.assertEquals("{\\i hallo}", formatter.format("\\textit{hallo}")); - Assert.assertEquals("{\\i hallo}", formatter.format("{\\textit hallo}")); + assertEquals("{\\i hallo}", formatter.format("\\textit{hallo}")); + assertEquals("{\\i hallo}", formatter.format("{\\textit hallo}")); - Assert.assertEquals("{\\b hallo}", formatter.format("\\textbf{hallo}")); - Assert.assertEquals("{\\b hallo}", formatter.format("{\\textbf hallo}")); + assertEquals("{\\b hallo}", formatter.format("\\textbf{hallo}")); + assertEquals("{\\b hallo}", formatter.format("{\\textbf hallo}")); } @Test public void testComplicated() { - Assert.assertEquals("R\\u233eflexions sur le timing de la quantit\\u233e {\\u230ae} should be \\u230ae", + assertEquals("R\\u233eflexions sur le timing de la quantit\\u233e {\\u230ae} should be \\u230ae", formatter.format("Réflexions sur le timing de la quantité {\\ae} should be æ")); } @Test public void testComplicated2() { - Assert.assertEquals("h\\'e1ll{\\u339oe}", formatter.format("h\\'all{\\oe}")); + assertEquals("h\\'e1ll{\\u339oe}", formatter.format("h\\'all{\\oe}")); } @Test public void testComplicated3() { - Assert.assertEquals("Le c\\u339oeur d\\u233e\\u231cu mais l'\\u226ame plut\\u244ot na\\u239ive, Lou\\u255ys r" + + assertEquals("Le c\\u339oeur d\\u233e\\u231cu mais l'\\u226ame plut\\u244ot na\\u239ive, Lou\\u255ys r" + "\\u234eva de crapa\\u252?ter en cano\\u235e au del\\u224a des \\u238iles, pr\\u232es du m\\u228alstr" + "\\u246om o\\u249u br\\u251ulent les nov\\u230ae.", formatter.format("Le cœur déçu mais l'âme plutôt " + "naïve, Louÿs rêva de crapaüter en canoë au delà des îles, près du mälström où brûlent les novæ.")); @@ -67,7 +67,7 @@ public void testComplicated3() { @Test public void testComplicated4() { - Assert.assertEquals("l'\\u238ile exigu\\u235e\n" + + assertEquals("l'\\u238ile exigu\\u235e\n" + " O\\u249u l'ob\\u232ese jury m\\u251ur\n" + " F\\u234ete l'ha\\u239i volap\\u252?k,\n" + " \\u194Ane ex a\\u233equo au whist,\n" + @@ -80,109 +80,109 @@ public void testComplicated4() { @Test public void testComplicated5() { - Assert.assertEquals("\\u193Arv\\u237izt\\u369?r\\u337? t\\u252?k\\u246orf\\u250ur\\u243og\\u233ep", + assertEquals("\\u193Arv\\u237izt\\u369?r\\u337? t\\u252?k\\u246orf\\u250ur\\u243og\\u233ep", formatter.format("Árvíztűrő tükörfúrógép")); } @Test public void testComplicated6() { - Assert.assertEquals("Pchn\\u261a\\u263c w t\\u281e \\u322l\\u243od\\u378z je\\u380za lub o\\u347sm skrzy\\u324n fig" + assertEquals("Pchn\\u261a\\u263c w t\\u281e \\u322l\\u243od\\u378z je\\u380za lub o\\u347sm skrzy\\u324n fig" ,formatter.format("Pchnąć w tę łódź jeża lub ośm skrzyń fig")); } @Test public void testSpecialCharacters() { - Assert.assertEquals("\\'f3", formatter.format("\\'{o}")); // ó - Assert.assertEquals("\\'f2", formatter.format("\\`{o}")); // ò - Assert.assertEquals("\\'f4", formatter.format("\\^{o}")); // ô - Assert.assertEquals("\\'f6", formatter.format("\\\"{o}")); // ö - Assert.assertEquals("\\u245o", formatter.format("\\~{o}")); // õ - Assert.assertEquals("\\u333o", formatter.format("\\={o}")); - Assert.assertEquals("\\u335o", formatter.format("{\\uo}")); - Assert.assertEquals("\\u231c", formatter.format("{\\cc}")); // ç - Assert.assertEquals("{\\u339oe}", formatter.format("{\\oe}")); - Assert.assertEquals("{\\u338OE}", formatter.format("{\\OE}")); - Assert.assertEquals("{\\u230ae}", formatter.format("{\\ae}")); // æ - Assert.assertEquals("{\\u198AE}", formatter.format("{\\AE}")); // Æ - - Assert.assertEquals("", formatter.format("\\.{o}")); // ??? - Assert.assertEquals("", formatter.format("\\vo")); // ??? - Assert.assertEquals("", formatter.format("\\Ha")); // ã // ??? - Assert.assertEquals("", formatter.format("\\too")); - Assert.assertEquals("", formatter.format("\\do")); // ??? - Assert.assertEquals("", formatter.format("\\bo")); // ??? - Assert.assertEquals("\\u229a", formatter.format("{\\aa}")); // å - Assert.assertEquals("\\u197A", formatter.format("{\\AA}")); // Å - Assert.assertEquals("\\u248o", formatter.format("{\\o}")); // ø - Assert.assertEquals("\\u216O", formatter.format("{\\O}")); // Ø - Assert.assertEquals("\\u322l", formatter.format("{\\l}")); - Assert.assertEquals("\\u321L", formatter.format("{\\L}")); - Assert.assertEquals("\\u223ss", formatter.format("{\\ss}")); // ß - Assert.assertEquals("\\u191?", formatter.format("\\`?")); // ¿ - Assert.assertEquals("\\u161!", formatter.format("\\`!")); // ¡ - - Assert.assertEquals("", formatter.format("\\dag")); - Assert.assertEquals("", formatter.format("\\ddag")); - Assert.assertEquals("\\u167S", formatter.format("{\\S}")); // § - Assert.assertEquals("\\u182P", formatter.format("{\\P}")); // ¶ - Assert.assertEquals("\\u169?", formatter.format("{\\copyright}")); // © - Assert.assertEquals("\\u163?", formatter.format("{\\pounds}")); // £ + assertEquals("\\'f3", formatter.format("\\'{o}")); // ó + assertEquals("\\'f2", formatter.format("\\`{o}")); // ò + assertEquals("\\'f4", formatter.format("\\^{o}")); // ô + assertEquals("\\'f6", formatter.format("\\\"{o}")); // ö + assertEquals("\\u245o", formatter.format("\\~{o}")); // õ + assertEquals("\\u333o", formatter.format("\\={o}")); + assertEquals("\\u335o", formatter.format("{\\uo}")); + assertEquals("\\u231c", formatter.format("{\\cc}")); // ç + assertEquals("{\\u339oe}", formatter.format("{\\oe}")); + assertEquals("{\\u338OE}", formatter.format("{\\OE}")); + assertEquals("{\\u230ae}", formatter.format("{\\ae}")); // æ + assertEquals("{\\u198AE}", formatter.format("{\\AE}")); // Æ + + assertEquals("", formatter.format("\\.{o}")); // ??? + assertEquals("", formatter.format("\\vo")); // ??? + assertEquals("", formatter.format("\\Ha")); // ã // ??? + assertEquals("", formatter.format("\\too")); + assertEquals("", formatter.format("\\do")); // ??? + assertEquals("", formatter.format("\\bo")); // ??? + assertEquals("\\u229a", formatter.format("{\\aa}")); // å + assertEquals("\\u197A", formatter.format("{\\AA}")); // Å + assertEquals("\\u248o", formatter.format("{\\o}")); // ø + assertEquals("\\u216O", formatter.format("{\\O}")); // Ø + assertEquals("\\u322l", formatter.format("{\\l}")); + assertEquals("\\u321L", formatter.format("{\\L}")); + assertEquals("\\u223ss", formatter.format("{\\ss}")); // ß + assertEquals("\\u191?", formatter.format("\\`?")); // ¿ + assertEquals("\\u161!", formatter.format("\\`!")); // ¡ + + assertEquals("", formatter.format("\\dag")); + assertEquals("", formatter.format("\\ddag")); + assertEquals("\\u167S", formatter.format("{\\S}")); // § + assertEquals("\\u182P", formatter.format("{\\P}")); // ¶ + assertEquals("\\u169?", formatter.format("{\\copyright}")); // © + assertEquals("\\u163?", formatter.format("{\\pounds}")); // £ } @Test public void testRTFCharacters(){ - Assert.assertEquals("\\'e0",formatter.format("\\`{a}")); - Assert.assertEquals("\\'e8",formatter.format("\\`{e}")); - Assert.assertEquals("\\'ec",formatter.format("\\`{i}")); - Assert.assertEquals("\\'f2",formatter.format("\\`{o}")); - Assert.assertEquals("\\'f9",formatter.format("\\`{u}")); - - Assert.assertEquals("\\'e1",formatter.format("\\'a")); - Assert.assertEquals("\\'e9",formatter.format("\\'e")); - Assert.assertEquals("\\'ed",formatter.format("\\'i")); - Assert.assertEquals("\\'f3",formatter.format("\\'o")); - Assert.assertEquals("\\'fa",formatter.format("\\'u")); - - Assert.assertEquals("\\'e2",formatter.format("\\^a")); - Assert.assertEquals("\\'ea",formatter.format("\\^e")); - Assert.assertEquals("\\'ee",formatter.format("\\^i")); - Assert.assertEquals("\\'f4",formatter.format("\\^o")); - Assert.assertEquals("\\'fa",formatter.format("\\^u")); - - Assert.assertEquals("\\'e4",formatter.format("\\\"a")); - Assert.assertEquals("\\'eb",formatter.format("\\\"e")); - Assert.assertEquals("\\'ef",formatter.format("\\\"i")); - Assert.assertEquals("\\'f6",formatter.format("\\\"o")); - Assert.assertEquals("\\u252u",formatter.format("\\\"u")); - - Assert.assertEquals("\\'f1",formatter.format("\\~n")); + assertEquals("\\'e0",formatter.format("\\`{a}")); + assertEquals("\\'e8",formatter.format("\\`{e}")); + assertEquals("\\'ec",formatter.format("\\`{i}")); + assertEquals("\\'f2",formatter.format("\\`{o}")); + assertEquals("\\'f9",formatter.format("\\`{u}")); + + assertEquals("\\'e1",formatter.format("\\'a")); + assertEquals("\\'e9",formatter.format("\\'e")); + assertEquals("\\'ed",formatter.format("\\'i")); + assertEquals("\\'f3",formatter.format("\\'o")); + assertEquals("\\'fa",formatter.format("\\'u")); + + assertEquals("\\'e2",formatter.format("\\^a")); + assertEquals("\\'ea",formatter.format("\\^e")); + assertEquals("\\'ee",formatter.format("\\^i")); + assertEquals("\\'f4",formatter.format("\\^o")); + assertEquals("\\'fa",formatter.format("\\^u")); + + assertEquals("\\'e4",formatter.format("\\\"a")); + assertEquals("\\'eb",formatter.format("\\\"e")); + assertEquals("\\'ef",formatter.format("\\\"i")); + assertEquals("\\'f6",formatter.format("\\\"o")); + assertEquals("\\u252u",formatter.format("\\\"u")); + + assertEquals("\\'f1",formatter.format("\\~n")); } @Test public void testRTFCharactersCapital() { - Assert.assertEquals("\\'c0",formatter.format("\\`A")); - Assert.assertEquals("\\'c8",formatter.format("\\`E")); - Assert.assertEquals("\\'cc",formatter.format("\\`I")); - Assert.assertEquals("\\'d2",formatter.format("\\`O")); - Assert.assertEquals("\\'d9",formatter.format("\\`U")); - - Assert.assertEquals("\\'c1",formatter.format("\\'A")); - Assert.assertEquals("\\'c9",formatter.format("\\'E")); - Assert.assertEquals("\\'cd",formatter.format("\\'I")); - Assert.assertEquals("\\'d3",formatter.format("\\'O")); - Assert.assertEquals("\\'da",formatter.format("\\'U")); - - Assert.assertEquals("\\'c2",formatter.format("\\^A")); - Assert.assertEquals("\\'ca",formatter.format("\\^E")); - Assert.assertEquals("\\'ce",formatter.format("\\^I")); - Assert.assertEquals("\\'d4",formatter.format("\\^O")); - Assert.assertEquals("\\'db",formatter.format("\\^U")); - - Assert.assertEquals("\\'c4",formatter.format("\\\"A")); - Assert.assertEquals("\\'cb",formatter.format("\\\"E")); - Assert.assertEquals("\\'cf",formatter.format("\\\"I")); - Assert.assertEquals("\\'d6",formatter.format("\\\"O")); - Assert.assertEquals("\\'dc",formatter.format("\\\"U")); + assertEquals("\\'c0",formatter.format("\\`A")); + assertEquals("\\'c8",formatter.format("\\`E")); + assertEquals("\\'cc",formatter.format("\\`I")); + assertEquals("\\'d2",formatter.format("\\`O")); + assertEquals("\\'d9",formatter.format("\\`U")); + + assertEquals("\\'c1",formatter.format("\\'A")); + assertEquals("\\'c9",formatter.format("\\'E")); + assertEquals("\\'cd",formatter.format("\\'I")); + assertEquals("\\'d3",formatter.format("\\'O")); + assertEquals("\\'da",formatter.format("\\'U")); + + assertEquals("\\'c2",formatter.format("\\^A")); + assertEquals("\\'ca",formatter.format("\\^E")); + assertEquals("\\'ce",formatter.format("\\^I")); + assertEquals("\\'d4",formatter.format("\\^O")); + assertEquals("\\'db",formatter.format("\\^U")); + + assertEquals("\\'c4",formatter.format("\\\"A")); + assertEquals("\\'cb",formatter.format("\\\"E")); + assertEquals("\\'cf",formatter.format("\\\"I")); + assertEquals("\\'d6",formatter.format("\\\"O")); + assertEquals("\\'dc",formatter.format("\\\"U")); } } diff --git a/src/test/java/org/jabref/logic/layout/format/RemoveBracketsAddCommaTest.java b/src/test/java/org/jabref/logic/layout/format/RemoveBracketsAddCommaTest.java index 7c1bb212cd8..e805bbf5490 100644 --- a/src/test/java/org/jabref/logic/layout/format/RemoveBracketsAddCommaTest.java +++ b/src/test/java/org/jabref/logic/layout/format/RemoveBracketsAddCommaTest.java @@ -2,15 +2,15 @@ import org.jabref.logic.layout.LayoutFormatter; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class RemoveBracketsAddCommaTest { private LayoutFormatter formatter; - @Before + @BeforeEach public void setUp() { formatter = new RemoveBracketsAddComma(); } diff --git a/src/test/java/org/jabref/logic/layout/format/RemoveBracketsTest.java b/src/test/java/org/jabref/logic/layout/format/RemoveBracketsTest.java index fff8e9e8775..48c904c40bc 100644 --- a/src/test/java/org/jabref/logic/layout/format/RemoveBracketsTest.java +++ b/src/test/java/org/jabref/logic/layout/format/RemoveBracketsTest.java @@ -2,15 +2,15 @@ import org.jabref.logic.layout.LayoutFormatter; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class RemoveBracketsTest { private LayoutFormatter formatter; - @Before + @BeforeEach public void setUp() { formatter = new RemoveBrackets(); } diff --git a/src/test/java/org/jabref/logic/layout/format/RemoveTildeTest.java b/src/test/java/org/jabref/logic/layout/format/RemoveTildeTest.java index aa96bd3c53e..31406596bfe 100644 --- a/src/test/java/org/jabref/logic/layout/format/RemoveTildeTest.java +++ b/src/test/java/org/jabref/logic/layout/format/RemoveTildeTest.java @@ -2,27 +2,27 @@ import org.jabref.logic.layout.LayoutFormatter; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class RemoveTildeTest { private LayoutFormatter formatter; - @Before + @BeforeEach public void setUp() { formatter = new RemoveTilde(); } @Test public void testFormatString() { - Assert.assertEquals("", formatter.format("")); - Assert.assertEquals("simple", formatter.format("simple")); - Assert.assertEquals(" ", formatter.format("~")); - Assert.assertEquals(" ", formatter.format("~~~")); - Assert.assertEquals(" \\~ ", formatter.format("~\\~~")); - Assert.assertEquals("\\\\ ", formatter.format("\\\\~")); - Assert.assertEquals("Doe Joe and Jane, M. and Kamp, J. A.", formatter.format("Doe Joe and Jane, M. and Kamp, J.~A.")); - Assert.assertEquals("T\\~olkien, J. R. R.", formatter.format("T\\~olkien, J.~R.~R.")); + assertEquals("", formatter.format("")); + assertEquals("simple", formatter.format("simple")); + assertEquals(" ", formatter.format("~")); + assertEquals(" ", formatter.format("~~~")); + assertEquals(" \\~ ", formatter.format("~\\~~")); + assertEquals("\\\\ ", formatter.format("\\\\~")); + assertEquals("Doe Joe and Jane, M. and Kamp, J. A.", formatter.format("Doe Joe and Jane, M. and Kamp, J.~A.")); + assertEquals("T\\~olkien, J. R. R.", formatter.format("T\\~olkien, J.~R.~R.")); } } diff --git a/src/test/java/org/jabref/logic/layout/format/RemoveWhitespaceTest.java b/src/test/java/org/jabref/logic/layout/format/RemoveWhitespaceTest.java index f80eb543a54..96e92bbac0b 100644 --- a/src/test/java/org/jabref/logic/layout/format/RemoveWhitespaceTest.java +++ b/src/test/java/org/jabref/logic/layout/format/RemoveWhitespaceTest.java @@ -1,9 +1,9 @@ package org.jabref.logic.layout.format; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; public class RemoveWhitespaceTest { diff --git a/src/test/java/org/jabref/logic/layout/format/ReplaceTest.java b/src/test/java/org/jabref/logic/layout/format/ReplaceTest.java index ef1638f29e7..e5653beb9f7 100644 --- a/src/test/java/org/jabref/logic/layout/format/ReplaceTest.java +++ b/src/test/java/org/jabref/logic/layout/format/ReplaceTest.java @@ -2,8 +2,8 @@ import org.jabref.logic.layout.ParamLayoutFormatter; -import org.junit.Assert; -import org.junit.Test; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class ReplaceTest { @@ -11,40 +11,40 @@ public class ReplaceTest { public void testSimpleText() { ParamLayoutFormatter a = new Replace(); a.setArgument("Bob,Ben"); - Assert.assertEquals("Ben Bruce", a.format("Bob Bruce")); + assertEquals("Ben Bruce", a.format("Bob Bruce")); } @Test public void testSimpleTextNoHit() { ParamLayoutFormatter a = new Replace(); a.setArgument("Bob,Ben"); - Assert.assertEquals("Jolly Jumper", a.format("Jolly Jumper")); + assertEquals("Jolly Jumper", a.format("Jolly Jumper")); } @Test public void testFormatNull() { ParamLayoutFormatter a = new Replace(); a.setArgument("Eds.,Ed."); - Assert.assertEquals(null, a.format(null)); + assertEquals(null, a.format(null)); } @Test public void testFormatEmpty() { ParamLayoutFormatter a = new Replace(); a.setArgument("Eds.,Ed."); - Assert.assertEquals("", a.format("")); + assertEquals("", a.format("")); } @Test public void testNoArgumentSet() { ParamLayoutFormatter a = new Replace(); - Assert.assertEquals("Bob Bruce and Jolly Jumper", a.format("Bob Bruce and Jolly Jumper")); + assertEquals("Bob Bruce and Jolly Jumper", a.format("Bob Bruce and Jolly Jumper")); } @Test public void testNoProperArgument() { ParamLayoutFormatter a = new Replace(); a.setArgument("Eds."); - Assert.assertEquals("Bob Bruce and Jolly Jumper", a.format("Bob Bruce and Jolly Jumper")); + assertEquals("Bob Bruce and Jolly Jumper", a.format("Bob Bruce and Jolly Jumper")); } } diff --git a/src/test/java/org/jabref/logic/layout/format/RisKeywordsTest.java b/src/test/java/org/jabref/logic/layout/format/RisKeywordsTest.java index 2ae02021f35..3cf2333bab6 100644 --- a/src/test/java/org/jabref/logic/layout/format/RisKeywordsTest.java +++ b/src/test/java/org/jabref/logic/layout/format/RisKeywordsTest.java @@ -2,9 +2,9 @@ import org.jabref.logic.util.OS; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class RisKeywordsTest { diff --git a/src/test/java/org/jabref/logic/layout/format/RisMonthTest.java b/src/test/java/org/jabref/logic/layout/format/RisMonthTest.java index 40d87e2b3a8..b3880bec7cb 100644 --- a/src/test/java/org/jabref/logic/layout/format/RisMonthTest.java +++ b/src/test/java/org/jabref/logic/layout/format/RisMonthTest.java @@ -1,8 +1,8 @@ package org.jabref.logic.layout.format; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class RisMonthTest { diff --git a/src/test/java/org/jabref/logic/layout/format/ToLowerCaseTest.java b/src/test/java/org/jabref/logic/layout/format/ToLowerCaseTest.java index 9feb7b566ad..59ce12216b5 100644 --- a/src/test/java/org/jabref/logic/layout/format/ToLowerCaseTest.java +++ b/src/test/java/org/jabref/logic/layout/format/ToLowerCaseTest.java @@ -1,9 +1,9 @@ package org.jabref.logic.layout.format; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; public class ToLowerCaseTest { diff --git a/src/test/java/org/jabref/logic/layout/format/ToUpperCaseTest.java b/src/test/java/org/jabref/logic/layout/format/ToUpperCaseTest.java index 40ae527c155..b0ca246bdd9 100644 --- a/src/test/java/org/jabref/logic/layout/format/ToUpperCaseTest.java +++ b/src/test/java/org/jabref/logic/layout/format/ToUpperCaseTest.java @@ -1,9 +1,9 @@ package org.jabref.logic.layout.format; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; public class ToUpperCaseTest { diff --git a/src/test/java/org/jabref/logic/layout/format/WrapContentTest.java b/src/test/java/org/jabref/logic/layout/format/WrapContentTest.java index 64d53167238..58e9e54c94e 100644 --- a/src/test/java/org/jabref/logic/layout/format/WrapContentTest.java +++ b/src/test/java/org/jabref/logic/layout/format/WrapContentTest.java @@ -2,8 +2,8 @@ import org.jabref.logic.layout.ParamLayoutFormatter; -import org.junit.Assert; -import org.junit.Test; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; public class WrapContentTest { @@ -11,54 +11,54 @@ public class WrapContentTest { public void testSimpleText() { ParamLayoutFormatter a = new WrapContent(); a.setArgument("<,>"); - Assert.assertEquals("", a.format("Bob")); + assertEquals("", a.format("Bob")); } @Test public void testEmptyStart() { ParamLayoutFormatter a = new WrapContent(); a.setArgument(",:"); - Assert.assertEquals("Bob:", a.format("Bob")); + assertEquals("Bob:", a.format("Bob")); } @Test public void testEmptyEnd() { ParamLayoutFormatter a = new WrapContent(); a.setArgument("Content: ,"); - Assert.assertEquals("Content: Bob", a.format("Bob")); + assertEquals("Content: Bob", a.format("Bob")); } @Test public void testEscaping() { ParamLayoutFormatter a = new WrapContent(); a.setArgument("Name\\,Field\\,,\\,Author"); - Assert.assertEquals("Name,Field,Bob,Author", a.format("Bob")); + assertEquals("Name,Field,Bob,Author", a.format("Bob")); } @Test public void testFormatNullExpectNothingAdded() { ParamLayoutFormatter a = new WrapContent(); a.setArgument("Eds.,Ed."); - Assert.assertEquals(null, a.format(null)); + assertEquals(null, a.format(null)); } @Test public void testFormatEmptyExpectNothingAdded() { ParamLayoutFormatter a = new WrapContent(); a.setArgument("Eds.,Ed."); - Assert.assertEquals("", a.format("")); + assertEquals("", a.format("")); } @Test public void testNoArgumentSetExpectNothingAdded() { ParamLayoutFormatter a = new WrapContent(); - Assert.assertEquals("Bob Bruce and Jolly Jumper", a.format("Bob Bruce and Jolly Jumper")); + assertEquals("Bob Bruce and Jolly Jumper", a.format("Bob Bruce and Jolly Jumper")); } @Test public void testNoProperArgumentExpectNothingAdded() { ParamLayoutFormatter a = new WrapContent(); a.setArgument("Eds."); - Assert.assertEquals("Bob Bruce and Jolly Jumper", a.format("Bob Bruce and Jolly Jumper")); + assertEquals("Bob Bruce and Jolly Jumper", a.format("Bob Bruce and Jolly Jumper")); } } diff --git a/src/test/java/org/jabref/logic/layout/format/WrapFileLinksTest.java b/src/test/java/org/jabref/logic/layout/format/WrapFileLinksTest.java index 08861c389d3..05dfc422f2b 100644 --- a/src/test/java/org/jabref/logic/layout/format/WrapFileLinksTest.java +++ b/src/test/java/org/jabref/logic/layout/format/WrapFileLinksTest.java @@ -4,11 +4,11 @@ import java.io.IOException; import java.util.Collections; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; public class WrapFileLinksTest { @@ -16,7 +16,7 @@ public class WrapFileLinksTest { private WrapFileLinks formatter; - @Before + @BeforeEach public void setUp() { FileLinkPreferences preferences = new FileLinkPreferences(Collections.emptyList(), Collections.emptyList()); formatter = new WrapFileLinks(preferences); @@ -32,10 +32,9 @@ public void testNull() { assertEquals("", formatter.format(null)); } - @Test(expected = NullPointerException.class) public void testNoFormatSetNonEmptyString() { - formatter.format("test.pdf"); - fail(); + assertThrows(NullPointerException.class, () -> formatter.format("test.pdf")); + } @Test diff --git a/src/test/java/org/jabref/logic/msbib/MsBibAuthorTest.java b/src/test/java/org/jabref/logic/msbib/MsBibAuthorTest.java index 9a7dd384ca8..328f90566ad 100644 --- a/src/test/java/org/jabref/logic/msbib/MsBibAuthorTest.java +++ b/src/test/java/org/jabref/logic/msbib/MsBibAuthorTest.java @@ -2,9 +2,9 @@ import org.jabref.model.entry.Author; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class MsBibAuthorTest { diff --git a/src/test/java/org/jabref/logic/net/URLDownloadTest.java b/src/test/java/org/jabref/logic/net/URLDownloadTest.java index 0f17db0851c..2f830ce98e3 100644 --- a/src/test/java/org/jabref/logic/net/URLDownloadTest.java +++ b/src/test/java/org/jabref/logic/net/URLDownloadTest.java @@ -6,8 +6,10 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Path; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; public class URLDownloadTest { @@ -15,15 +17,14 @@ public class URLDownloadTest { public void testStringDownloadWithSetEncoding() throws IOException { URLDownload dl = new URLDownload(new URL("http://www.google.com")); - Assert.assertTrue("google.com should contain google", dl.asString().contains("Google")); + assertTrue(dl.asString().contains("Google"), "google.com should contain google"); } @Test public void testStringDownload() throws IOException { URLDownload dl = new URLDownload(new URL("http://www.google.com")); - Assert.assertTrue("google.com should contain google", - dl.asString(StandardCharsets.UTF_8).contains("Google")); + assertTrue(dl.asString(StandardCharsets.UTF_8).contains("Google"), "google.com should contain google"); } @Test @@ -32,7 +33,7 @@ public void testFileDownload() throws IOException { try { URLDownload dl = new URLDownload(new URL("http://www.google.com")); dl.toFile(destination.toPath()); - Assert.assertTrue("file must exist", destination.exists()); + assertTrue(destination.exists(), "file must exist"); } finally { // cleanup if (!destination.delete()) { @@ -45,7 +46,7 @@ public void testFileDownload() throws IOException { public void testDetermineMimeType() throws IOException { URLDownload dl = new URLDownload(new URL("http://www.google.com")); - Assert.assertTrue(dl.getMimeType().startsWith("text/html")); + assertTrue(dl.getMimeType().startsWith("text/html")); } @Test @@ -53,7 +54,7 @@ public void downloadToTemporaryFilePathWithoutFileSavesAsTmpFile() throws IOExce URLDownload google = new URLDownload(new URL("http://www.google.com")); String path = google.toTemporaryFile().toString(); - Assert.assertTrue(path, path.endsWith(".tmp")); + assertTrue(path.endsWith(".tmp"), path); } @Test @@ -61,7 +62,7 @@ public void downloadToTemporaryFileKeepsName() throws IOException { URLDownload google = new URLDownload(new URL("https://github.com/JabRef/jabref/blob/master/LICENSE.md")); String path = google.toTemporaryFile().toString(); - Assert.assertTrue(path, path.contains("LICENSE") && path.endsWith(".md")); + assertTrue(path.contains("LICENSE") && path.endsWith(".md"), path); } @Test @@ -69,7 +70,7 @@ public void downloadOfFTPSucceeds() throws IOException { URLDownload ftp = new URLDownload(new URL("ftp://ftp.informatik.uni-stuttgart.de/pub/library/ncstrl.ustuttgart_fi/INPROC-2016-15/INPROC-2016-15.pdf")); Path path = ftp.toTemporaryFile(); - Assert.assertNotNull(path); + assertNotNull(path); } @Test @@ -77,7 +78,7 @@ public void downloadOfHttpSucceeds() throws IOException { URLDownload ftp = new URLDownload(new URL("http://www.jabref.org")); Path path = ftp.toTemporaryFile(); - Assert.assertNotNull(path); + assertNotNull(path); } @Test @@ -85,7 +86,7 @@ public void downloadOfHttpsSucceeds() throws IOException { URLDownload ftp = new URLDownload(new URL("https://www.jabref.org")); Path path = ftp.toTemporaryFile(); - Assert.assertNotNull(path); + assertNotNull(path); } } diff --git a/src/test/java/org/jabref/logic/net/URLUtilTest.java b/src/test/java/org/jabref/logic/net/URLUtilTest.java index 01cd062cd1b..69815f1cf3e 100644 --- a/src/test/java/org/jabref/logic/net/URLUtilTest.java +++ b/src/test/java/org/jabref/logic/net/URLUtilTest.java @@ -1,76 +1,74 @@ package org.jabref.logic.net; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; public class URLUtilTest { + @Test public void cleanGoogleSearchURL() throws Exception { // empty text - Assert.assertEquals("", URLUtil.cleanGoogleSearchURL("")); - Assert.assertEquals(" ", URLUtil.cleanGoogleSearchURL(" ")); + assertEquals("", URLUtil.cleanGoogleSearchURL("")); + assertEquals(" ", URLUtil.cleanGoogleSearchURL(" ")); // no URL - Assert.assertEquals("this is no url!", URLUtil.cleanGoogleSearchURL("this is no url!")); + assertEquals("this is no url!", URLUtil.cleanGoogleSearchURL("this is no url!")); // no Google search URL - Assert.assertEquals("http://dl.acm.org/citation.cfm?id=321811", URLUtil.cleanGoogleSearchURL("http://dl.acm.org/citation.cfm?id=321811")); + assertEquals("http://dl.acm.org/citation.cfm?id=321811", URLUtil.cleanGoogleSearchURL("http://dl.acm.org/citation.cfm?id=321811")); // malformed Google URL - Assert.assertEquals("https://www.google.de/url♥", URLUtil.cleanGoogleSearchURL("https://www.google.de/url♥")); + assertEquals("https://www.google.de/url♥", URLUtil.cleanGoogleSearchURL("https://www.google.de/url♥")); // no queries - Assert.assertEquals("https://www.google.de/url", URLUtil.cleanGoogleSearchURL("https://www.google.de/url")); - Assert.assertEquals("https://www.google.de/url?", URLUtil.cleanGoogleSearchURL("https://www.google.de/url?")); + assertEquals("https://www.google.de/url", URLUtil.cleanGoogleSearchURL("https://www.google.de/url")); + assertEquals("https://www.google.de/url?", URLUtil.cleanGoogleSearchURL("https://www.google.de/url?")); // no multiple queries - Assert.assertEquals("https://www.google.de/url?key=value", URLUtil.cleanGoogleSearchURL("https://www.google.de/url?key=value")); + assertEquals("https://www.google.de/url?key=value", URLUtil.cleanGoogleSearchURL("https://www.google.de/url?key=value")); // no key values - Assert.assertEquals("https://www.google.de/url?key", URLUtil.cleanGoogleSearchURL("https://www.google.de/url?key")); - Assert.assertEquals("https://www.google.de/url?url", URLUtil.cleanGoogleSearchURL("https://www.google.de/url?url")); - Assert.assertEquals("https://www.google.de/url?key=", URLUtil.cleanGoogleSearchURL("https://www.google.de/url?key=")); + assertEquals("https://www.google.de/url?key", URLUtil.cleanGoogleSearchURL("https://www.google.de/url?key")); + assertEquals("https://www.google.de/url?url", URLUtil.cleanGoogleSearchURL("https://www.google.de/url?url")); + assertEquals("https://www.google.de/url?key=", URLUtil.cleanGoogleSearchURL("https://www.google.de/url?key=")); // no url param - Assert.assertEquals("https://www.google.de/url?key=value&key2=value2", URLUtil.cleanGoogleSearchURL("https://www.google.de/url?key=value&key2=value2")); + assertEquals("https://www.google.de/url?key=value&key2=value2", URLUtil.cleanGoogleSearchURL("https://www.google.de/url?key=value&key2=value2")); // no url param value - Assert.assertEquals("https://www.google.de/url?url=", URLUtil.cleanGoogleSearchURL("https://www.google.de/url?url=")); + assertEquals("https://www.google.de/url?url=", URLUtil.cleanGoogleSearchURL("https://www.google.de/url?url=")); // url param value no URL - Assert.assertEquals("https://www.google.de/url?url=this+is+no+url", URLUtil.cleanGoogleSearchURL("https://www.google.de/url?url=this+is+no+url")); + assertEquals("https://www.google.de/url?url=this+is+no+url", URLUtil.cleanGoogleSearchURL("https://www.google.de/url?url=this+is+no+url")); // Http - Assert.assertEquals( + assertEquals( "http://moz.com/ugc/the-ultimate-guide-to-the-google-search-parameters", - URLUtil.cleanGoogleSearchURL("http://www.google.de/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cad=rja&uact=8&ved=0CCEQFjAAahUKEwjJurHd2sfHAhWBsxQKHSrEAaM&url=http%3A%2F%2Fmoz.com%2Fugc%2Fthe-ultimate-guide-to-the-google-search-parameters&ei=0THeVYmOJIHnUqqIh5gK&usg=AFQjCNHnid_r_d2LP8_MqvI7lQnTC3lB_g&sig2=ICzxDroG2ENTJSUGmdhI2w") - ); + URLUtil.cleanGoogleSearchURL("http://www.google.de/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cad=rja&uact=8&ved=0CCEQFjAAahUKEwjJurHd2sfHAhWBsxQKHSrEAaM&url=http%3A%2F%2Fmoz.com%2Fugc%2Fthe-ultimate-guide-to-the-google-search-parameters&ei=0THeVYmOJIHnUqqIh5gK&usg=AFQjCNHnid_r_d2LP8_MqvI7lQnTC3lB_g&sig2=ICzxDroG2ENTJSUGmdhI2w")); // Https - Assert.assertEquals( + assertEquals( "https://moz.com/ugc/the-ultimate-guide-to-the-google-search-parameters", - URLUtil.cleanGoogleSearchURL("https://www.google.de/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cad=rja&uact=8&ved=0CCEQFjAAahUKEwjJurHd2sfHAhWBsxQKHSrEAaM&url=https%3A%2F%2Fmoz.com%2Fugc%2Fthe-ultimate-guide-to-the-google-search-parameters&ei=0THeVYmOJIHnUqqIh5gK&usg=AFQjCNHnid_r_d2LP8_MqvI7lQnTC3lB_g&sig2=ICzxDroG2ENTJSUGmdhI2w") - ); + URLUtil.cleanGoogleSearchURL("https://www.google.de/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cad=rja&uact=8&ved=0CCEQFjAAahUKEwjJurHd2sfHAhWBsxQKHSrEAaM&url=https%3A%2F%2Fmoz.com%2Fugc%2Fthe-ultimate-guide-to-the-google-search-parameters&ei=0THeVYmOJIHnUqqIh5gK&usg=AFQjCNHnid_r_d2LP8_MqvI7lQnTC3lB_g&sig2=ICzxDroG2ENTJSUGmdhI2w")); // root domain - Assert.assertEquals( + assertEquals( "https://moz.com/ugc/the-ultimate-guide-to-the-google-search-parameters", - URLUtil.cleanGoogleSearchURL("https://google.de/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cad=rja&uact=8&ved=0CCEQFjAAahUKEwjJurHd2sfHAhWBsxQKHSrEAaM&url=https%3A%2F%2Fmoz.com%2Fugc%2Fthe-ultimate-guide-to-the-google-search-parameters&ei=0THeVYmOJIHnUqqIh5gK&usg=AFQjCNHnid_r_d2LP8_MqvI7lQnTC3lB_g&sig2=ICzxDroG2ENTJSUGmdhI2w") - ); + URLUtil.cleanGoogleSearchURL("https://google.de/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cad=rja&uact=8&ved=0CCEQFjAAahUKEwjJurHd2sfHAhWBsxQKHSrEAaM&url=https%3A%2F%2Fmoz.com%2Fugc%2Fthe-ultimate-guide-to-the-google-search-parameters&ei=0THeVYmOJIHnUqqIh5gK&usg=AFQjCNHnid_r_d2LP8_MqvI7lQnTC3lB_g&sig2=ICzxDroG2ENTJSUGmdhI2w")); // foreign domain - Assert.assertEquals( + assertEquals( "https://moz.com/ugc/the-ultimate-guide-to-the-google-search-parameters", - URLUtil.cleanGoogleSearchURL("https://www.google.fr/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cad=rja&uact=8&ved=0CCEQFjAAahUKEwjJurHd2sfHAhWBsxQKHSrEAaM&url=https%3A%2F%2Fmoz.com%2Fugc%2Fthe-ultimate-guide-to-the-google-search-parameters&ei=0THeVYmOJIHnUqqIh5gK&usg=AFQjCNHnid_r_d2LP8_MqvI7lQnTC3lB_g&sig2=ICzxDroG2ENTJSUGmdhI2w") - ); + URLUtil.cleanGoogleSearchURL("https://www.google.fr/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cad=rja&uact=8&ved=0CCEQFjAAahUKEwjJurHd2sfHAhWBsxQKHSrEAaM&url=https%3A%2F%2Fmoz.com%2Fugc%2Fthe-ultimate-guide-to-the-google-search-parameters&ei=0THeVYmOJIHnUqqIh5gK&usg=AFQjCNHnid_r_d2LP8_MqvI7lQnTC3lB_g&sig2=ICzxDroG2ENTJSUGmdhI2w")); // foreign domain co.uk - Assert.assertEquals( + assertEquals( "https://moz.com/ugc/the-ultimate-guide-to-the-google-search-parameters", - URLUtil.cleanGoogleSearchURL("https://www.google.co.uk/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cad=rja&uact=8&ved=0CCEQFjAAahUKEwjJurHd2sfHAhWBsxQKHSrEAaM&url=https%3A%2F%2Fmoz.com%2Fugc%2Fthe-ultimate-guide-to-the-google-search-parameters&ei=0THeVYmOJIHnUqqIh5gK&usg=AFQjCNHnid_r_d2LP8_MqvI7lQnTC3lB_g&sig2=ICzxDroG2ENTJSUGmdhI2w") - ); + URLUtil.cleanGoogleSearchURL("https://www.google.co.uk/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cad=rja&uact=8&ved=0CCEQFjAAahUKEwjJurHd2sfHAhWBsxQKHSrEAaM&url=https%3A%2F%2Fmoz.com%2Fugc%2Fthe-ultimate-guide-to-the-google-search-parameters&ei=0THeVYmOJIHnUqqIh5gK&usg=AFQjCNHnid_r_d2LP8_MqvI7lQnTC3lB_g&sig2=ICzxDroG2ENTJSUGmdhI2w")); // accept ftp results - Assert.assertEquals( + assertEquals( "ftp://moz.com/ugc/the-ultimate-guide-to-the-google-search-parameters", - URLUtil.cleanGoogleSearchURL("https://www.google.fr/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cad=rja&uact=8&ved=0CCEQFjAAahUKEwjJurHd2sfHAhWBsxQKHSrEAaM&url=ftp%3A%2F%2Fmoz.com%2Fugc%2Fthe-ultimate-guide-to-the-google-search-parameters&ei=0THeVYmOJIHnUqqIh5gK&usg=AFQjCNHnid_r_d2LP8_MqvI7lQnTC3lB_g&sig2=ICzxDroG2ENTJSUGmdhI2w") - ); + URLUtil.cleanGoogleSearchURL("https://www.google.fr/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cad=rja&uact=8&ved=0CCEQFjAAahUKEwjJurHd2sfHAhWBsxQKHSrEAaM&url=ftp%3A%2F%2Fmoz.com%2Fugc%2Fthe-ultimate-guide-to-the-google-search-parameters&ei=0THeVYmOJIHnUqqIh5gK&usg=AFQjCNHnid_r_d2LP8_MqvI7lQnTC3lB_g&sig2=ICzxDroG2ENTJSUGmdhI2w")); } @Test public void isURLshouldAcceptValidURL() { - Assert.assertTrue(URLUtil.isURL("http://www.google.com")); - Assert.assertTrue(URLUtil.isURL("https://www.google.com")); + assertTrue(URLUtil.isURL("http://www.google.com")); + assertTrue(URLUtil.isURL("https://www.google.com")); } @Test public void isURLshouldRejectInvalidURL() { - Assert.assertFalse(URLUtil.isURL("www.google.com")); - Assert.assertFalse(URLUtil.isURL("google.com")); + assertFalse(URLUtil.isURL("www.google.com")); + assertFalse(URLUtil.isURL("google.com")); } } diff --git a/src/test/java/org/jabref/logic/openoffice/CitationEntryTest.java b/src/test/java/org/jabref/logic/openoffice/CitationEntryTest.java index 5e6bfa90815..3a9e7dc5050 100644 --- a/src/test/java/org/jabref/logic/openoffice/CitationEntryTest.java +++ b/src/test/java/org/jabref/logic/openoffice/CitationEntryTest.java @@ -4,10 +4,10 @@ import org.junit.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; public class CitationEntryTest { diff --git a/src/test/java/org/jabref/logic/openoffice/OOBibStyleTest.java b/src/test/java/org/jabref/logic/openoffice/OOBibStyleTest.java index e133e916180..485bcdfe64a 100644 --- a/src/test/java/org/jabref/logic/openoffice/OOBibStyleTest.java +++ b/src/test/java/org/jabref/logic/openoffice/OOBibStyleTest.java @@ -24,21 +24,21 @@ import org.jabref.model.entry.BibEntry; import org.jabref.model.util.DummyFileUpdateMonitor; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.mockito.Answers; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.mock; public class OOBibStyleTest { private LayoutFormatterPreferences layoutFormatterPreferences; private ImportFormatPreferences importFormatPreferences; - @Before + @BeforeEach public void setUp() { layoutFormatterPreferences = mock(LayoutFormatterPreferences.class, Answers.RETURNS_DEEP_STUBS); importFormatPreferences = mock(ImportFormatPreferences.class, Answers.RETURNS_DEEP_STUBS); diff --git a/src/test/java/org/jabref/logic/openoffice/OOPreFormatterTest.java b/src/test/java/org/jabref/logic/openoffice/OOPreFormatterTest.java index 33b0f1a1164..2c51434577e 100644 --- a/src/test/java/org/jabref/logic/openoffice/OOPreFormatterTest.java +++ b/src/test/java/org/jabref/logic/openoffice/OOPreFormatterTest.java @@ -1,8 +1,8 @@ package org.jabref.logic.openoffice; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class OOPreFormatterTest { diff --git a/src/test/java/org/jabref/logic/openoffice/StyleLoaderTest.java b/src/test/java/org/jabref/logic/openoffice/StyleLoaderTest.java index 2cd65802de0..f6ab59f1c35 100644 --- a/src/test/java/org/jabref/logic/openoffice/StyleLoaderTest.java +++ b/src/test/java/org/jabref/logic/openoffice/StyleLoaderTest.java @@ -11,14 +11,14 @@ import org.jabref.logic.layout.LayoutFormatterPreferences; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; +import org.junit.jupiter.api.Disabled; import org.mockito.Answers; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -40,22 +40,17 @@ public void setUp() { } - @Test(expected = NullPointerException.class) public void throwNPEWithNullPreferences() { - loader = new StyleLoader(null, layoutPreferences, mock(Charset.class)); - fail(); + assertThrows(NullPointerException.class, () -> loader = new StyleLoader(null, layoutPreferences, mock(Charset.class))); + } - @Test(expected = NullPointerException.class) public void throwNPEWithNullLayoutPreferences() { - loader = new StyleLoader(mock(OpenOfficePreferences.class), null, mock(Charset.class)); - fail(); + assertThrows(NullPointerException.class, () -> loader = new StyleLoader(mock(OpenOfficePreferences.class), null, mock(Charset.class))); } - @Test(expected = NullPointerException.class) public void throwNPEWithNullCharset() { - loader = new StyleLoader(mock(OpenOfficePreferences.class), layoutPreferences, null); - fail(); + assertThrows(NullPointerException.class, () -> loader = new StyleLoader(mock(OpenOfficePreferences.class), layoutPreferences, null)); } @Test @@ -125,7 +120,7 @@ public void testInitalizeWithOneExternalFileRemoveStyle() throws URISyntaxExcept } @Test - @Ignore("This tests the preferences that are mocked away") + @Disabled("This tests the preferences that are mocked away") public void testInitalizeWithOneExternalFileRemoveStyleUpdatesPreferences() throws URISyntaxException { String filename = Paths.get(StyleLoader.class.getResource(StyleLoader.DEFAULT_AUTHORYEAR_STYLE_PATH).toURI()) .toFile().getPath(); @@ -157,11 +152,11 @@ public void testAddSameStyleTwiceLeadsToOneMoreStyle() throws URISyntaxException assertEquals(beforeAdding + 1, loader.getStyles().size()); } - @Test(expected = NullPointerException.class) + public void testAddNullStyleThrowsNPE() { loader = new StyleLoader(preferences, layoutPreferences, encoding); - loader.addStyleIfValid(null); - fail(); + assertThrows(NullPointerException.class, () -> loader.addStyleIfValid(null)); + } @Test @@ -186,7 +181,7 @@ public void testGetStoredUsedStyle() { } @Test - @Ignore("This tests the preferences that are mocked away") + @Disabled("This tests the preferences that are mocked away") public void testGtDefaultUsedStyleWhenIncorrect() { when(preferences.getCurrentStyle()).thenReturn("ljlkjlkjnljnvdlsjniuhwelfhuewfhlkuewhfuwhelu"); loader = new StyleLoader(preferences, layoutPreferences, encoding); diff --git a/src/test/java/org/jabref/logic/pdf/EntryAnnotationImporterTest.java b/src/test/java/org/jabref/logic/pdf/EntryAnnotationImporterTest.java index 99689673e30..bbf62e29d7f 100644 --- a/src/test/java/org/jabref/logic/pdf/EntryAnnotationImporterTest.java +++ b/src/test/java/org/jabref/logic/pdf/EntryAnnotationImporterTest.java @@ -12,20 +12,20 @@ import org.jabref.model.entry.FieldName; import org.jabref.model.pdf.FileAnnotation; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; public class EntryAnnotationImporterTest { - private BibDatabaseContext databaseContext = mock(BibDatabaseContext.class); - private BibEntry entry = new BibEntry("EntryKey"); + private final BibDatabaseContext databaseContext = mock(BibDatabaseContext.class); + private final BibEntry entry = new BibEntry("EntryKey"); - @Before + @BeforeEach public void setUp() { when(databaseContext.getFileDirectoriesAsPaths(any())).thenReturn(Collections.singletonList(Paths.get("src/test/resources/pdfs/"))); } diff --git a/src/test/java/org/jabref/logic/pdf/PdfAnnotationImporterTest.java b/src/test/java/org/jabref/logic/pdf/PdfAnnotationImporterTest.java index e6fafd85d95..705f2f291bd 100644 --- a/src/test/java/org/jabref/logic/pdf/PdfAnnotationImporterTest.java +++ b/src/test/java/org/jabref/logic/pdf/PdfAnnotationImporterTest.java @@ -8,9 +8,10 @@ import org.jabref.model.pdf.FileAnnotation; import org.jabref.model.pdf.FileAnnotationType; -import org.junit.Test; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.Assert.assertEquals; public class PdfAnnotationImporterTest { diff --git a/src/test/java/org/jabref/logic/remote/RemotePreferencesTest.java b/src/test/java/org/jabref/logic/remote/RemotePreferencesTest.java index 9444e055a58..8094c70046d 100644 --- a/src/test/java/org/jabref/logic/remote/RemotePreferencesTest.java +++ b/src/test/java/org/jabref/logic/remote/RemotePreferencesTest.java @@ -1,19 +1,18 @@ package org.jabref.logic.remote; -import org.junit.Before; import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; public class RemotePreferencesTest { private RemotePreferences preferences; - @Before + @BeforeEach public void setUp() { preferences = new RemotePreferences(1000, true); } diff --git a/src/test/java/org/jabref/logic/remote/RemoteUtilTest.java b/src/test/java/org/jabref/logic/remote/RemoteUtilTest.java index b754e6c0f18..963d2755e47 100644 --- a/src/test/java/org/jabref/logic/remote/RemoteUtilTest.java +++ b/src/test/java/org/jabref/logic/remote/RemoteUtilTest.java @@ -1,30 +1,33 @@ package org.jabref.logic.remote; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; public class RemoteUtilTest { + @Test public void rejectPortNumberBelowZero() { - Assert.assertFalse("Port number must be non negative.", RemoteUtil.isUserPort(-55)); + assertFalse(RemoteUtil.isUserPort(-55), "Port number must be non negative."); } @Test public void rejectReservedSystemPorts() { - Assert.assertFalse("Port number must be outside reserved system range (0-1023).", RemoteUtil.isUserPort(0)); - Assert.assertFalse("Port number must be outside reserved system range (0-1023).", RemoteUtil.isUserPort(1023)); + assertFalse(RemoteUtil.isUserPort(0), "Port number must be outside reserved system range (0-1023)."); + assertFalse(RemoteUtil.isUserPort(1023), "Port number must be outside reserved system range (0-1023)."); } @Test public void rejectPortsAbove16Bits() { // 2 ^ 16 - 1 => 65535 - Assert.assertFalse("Port number should be below 65535.", RemoteUtil.isUserPort(65536)); + assertFalse(RemoteUtil.isUserPort(65536), "Port number should be below 65535."); } @Test public void acceptPortsAboveSystemPorts() { // ports 1024 -> 65535 - Assert.assertTrue("Port number in between 1024 and 65535 should be valid.", RemoteUtil.isUserPort(1024)); - Assert.assertTrue("Port number in between 1024 and 65535 should be valid.", RemoteUtil.isUserPort(65535)); + assertTrue(RemoteUtil.isUserPort(1024), "Port number in between 1024 and 65535 should be valid."); + assertTrue(RemoteUtil.isUserPort(65535), "Port number in between 1024 and 65535 should be valid."); } } diff --git a/src/test/java/org/jabref/logic/search/SearchQueryTest.java b/src/test/java/org/jabref/logic/search/SearchQueryTest.java index 4a49b7cc80c..d2eab079763 100644 --- a/src/test/java/org/jabref/logic/search/SearchQueryTest.java +++ b/src/test/java/org/jabref/logic/search/SearchQueryTest.java @@ -4,11 +4,12 @@ import org.jabref.model.entry.BibtexEntryTypes; import org.jabref.model.entry.FieldName; -import org.junit.Test; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; public class SearchQueryTest { diff --git a/src/test/java/org/jabref/logic/specialfields/SpecialFieldsUtilsTest.java b/src/test/java/org/jabref/logic/specialfields/SpecialFieldsUtilsTest.java index 792a09f3363..384e7fa0f2c 100644 --- a/src/test/java/org/jabref/logic/specialfields/SpecialFieldsUtilsTest.java +++ b/src/test/java/org/jabref/logic/specialfields/SpecialFieldsUtilsTest.java @@ -6,17 +6,16 @@ import org.jabref.model.FieldChange; import org.jabref.model.entry.BibEntry; - import org.jabref.model.entry.FieldName; import org.jabref.model.entry.Keyword; import org.jabref.model.entry.KeywordList; import org.jabref.model.entry.specialfields.SpecialField; -import org.junit.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; public class SpecialFieldsUtilsTest { diff --git a/src/test/java/org/jabref/logic/util/BracketedPatternTest.java b/src/test/java/org/jabref/logic/util/BracketedPatternTest.java index d10814053d1..b7b009b26dd 100644 --- a/src/test/java/org/jabref/logic/util/BracketedPatternTest.java +++ b/src/test/java/org/jabref/logic/util/BracketedPatternTest.java @@ -7,18 +7,20 @@ import org.jabref.model.entry.BibtexString; import org.jabref.model.entry.FieldName; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; public class BracketedPatternTest { + private BibEntry bibentry; private BibDatabase database; private BibEntry dbentry; - @Before + @BeforeEach public void setUp() throws Exception { bibentry = new BibEntry(); bibentry.setField("author", "O. Kitsune"); @@ -120,19 +122,19 @@ public void suppliedBibentryBracketExpansionTest() { assertEquals("2017_Gražulis_213", pattern.expand(another_bibentry, ';', another_database)); } - @Test(expected = NullPointerException.class) + @Test public void nullBibentryBracketExpansionTest() { BibDatabase another_database = null; BibEntry another_bibentry = null; BracketedPattern pattern = new BracketedPattern("[year]_[auth]_[firstpage]"); - pattern.expand(another_bibentry, ';', another_database); + assertThrows(NullPointerException.class, () -> pattern.expand(another_bibentry, ';', another_database)); } - @Test(expected = NullPointerException.class) + @Test public void bracketedExpressionDefaultConstructorTest() { BibDatabase another_database = null; BracketedPattern pattern = new BracketedPattern(); - pattern.expand(bibentry, ';', another_database); + assertThrows(NullPointerException.class, () -> pattern.expand(bibentry, ';', another_database)); } @Test diff --git a/src/test/java/org/jabref/logic/util/BuildInfoTest.java b/src/test/java/org/jabref/logic/util/BuildInfoTest.java index 578ca0e5d84..68f9d9c94b2 100644 --- a/src/test/java/org/jabref/logic/util/BuildInfoTest.java +++ b/src/test/java/org/jabref/logic/util/BuildInfoTest.java @@ -1,10 +1,10 @@ package org.jabref.logic.util; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; public class BuildInfoTest { diff --git a/src/test/java/org/jabref/logic/util/DevelopmentStageTest.java b/src/test/java/org/jabref/logic/util/DevelopmentStageTest.java index 54c93588e4c..f3c482fb309 100644 --- a/src/test/java/org/jabref/logic/util/DevelopmentStageTest.java +++ b/src/test/java/org/jabref/logic/util/DevelopmentStageTest.java @@ -2,8 +2,8 @@ import org.junit.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; public class DevelopmentStageTest { @@ -13,8 +13,7 @@ public void checkStabilityOrder() { assertTrue(Version.DevelopmentStage.BETA.isMoreStableThan(Version.DevelopmentStage.ALPHA)); assertTrue(Version.DevelopmentStage.STABLE.isMoreStableThan(Version.DevelopmentStage.BETA)); - assertEquals("It seems that the development stages have been changed, please adjust the test", 4, - Version.DevelopmentStage.values().length); + assertEquals(4, Version.DevelopmentStage.values().length, "It seems that the development stages have been changed, please adjust the test"); } @Test diff --git a/src/test/java/org/jabref/logic/util/FileTypeTest.java b/src/test/java/org/jabref/logic/util/FileTypeTest.java index 61c15a36e64..b9e89193dcc 100644 --- a/src/test/java/org/jabref/logic/util/FileTypeTest.java +++ b/src/test/java/org/jabref/logic/util/FileTypeTest.java @@ -1,8 +1,8 @@ package org.jabref.logic.util; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class FileTypeTest { diff --git a/src/test/java/org/jabref/logic/util/JavaVersionTest.java b/src/test/java/org/jabref/logic/util/JavaVersionTest.java index 13c951d8e43..5f67d084363 100644 --- a/src/test/java/org/jabref/logic/util/JavaVersionTest.java +++ b/src/test/java/org/jabref/logic/util/JavaVersionTest.java @@ -3,8 +3,11 @@ import java.util.ArrayList; import java.util.List; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + /** * Tests for ensuring we can compare most appearing version strings @@ -42,39 +45,39 @@ public void isJava9() throws Exception { // Check that all valid java versions below 9 are recognized as not java 9 for (String versionString : java) { final JavaVersion java8 = new JavaVersion(versionString); - Assert.assertFalse(java8.isJava9()); + assertFalse(java8.isJava9()); } // Check if all valid version 9 strings are recognized as being version 9 for (String version9String : java9) { final JavaVersion java9 = new JavaVersion(version9String); - Assert.assertTrue(java9.isJava9()); + assertTrue(java9.isJava9()); } // For impossible comparisons we assume it's not java 9 - Assert.assertFalse(nullCheck.isJava9()); - Assert.assertFalse(noSenseCheck.isJava9()); + assertFalse(nullCheck.isJava9()); + assertFalse(noSenseCheck.isJava9()); } @Test public void isAtLeast() throws Exception { final JavaVersion java8 = new JavaVersion("1.8"); for (String version8 : java) { - Assert.assertTrue(java8.isAtLeast(version8)); + assertTrue(java8.isAtLeast(version8)); final JavaVersion java8Example = new JavaVersion(version8); - Assert.assertTrue(java8Example.isAtLeast("1.5")); + assertTrue(java8Example.isAtLeast("1.5")); // Check if we optimistically return true if we cannot determine the result - Assert.assertTrue(java8Example.isAtLeast(null)); - Assert.assertTrue(nullCheck.isAtLeast(version8)); - Assert.assertTrue(noSenseCheck.isAtLeast(version8)); - Assert.assertTrue(java8Example.isAtLeast("useless")); + assertTrue(java8Example.isAtLeast(null)); + assertTrue(nullCheck.isAtLeast(version8)); + assertTrue(noSenseCheck.isAtLeast(version8)); + assertTrue(java8Example.isAtLeast("useless")); // Check against all java 9 entries in both directions for (String version9 : java9) { - Assert.assertFalse(java8Example.isAtLeast(version9)); + assertFalse(java8Example.isAtLeast(version9)); final JavaVersion java9 = new JavaVersion(version9); - Assert.assertTrue(java9.isAtLeast(version8)); + assertTrue(java9.isAtLeast(version8)); } } } diff --git a/src/test/java/org/jabref/logic/util/UpdateFieldTest.java b/src/test/java/org/jabref/logic/util/UpdateFieldTest.java index b25856a001a..d79d4014bff 100644 --- a/src/test/java/org/jabref/logic/util/UpdateFieldTest.java +++ b/src/test/java/org/jabref/logic/util/UpdateFieldTest.java @@ -5,13 +5,13 @@ import org.jabref.model.FieldChange; import org.jabref.model.entry.BibEntry; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; public class UpdateFieldTest { @@ -19,7 +19,7 @@ public class UpdateFieldTest { private BibEntry entry; - @Before + @BeforeEach public void setUp() throws Exception { entry = new BibEntry(); entry.setChanged(false); diff --git a/src/test/java/org/jabref/logic/util/VersionTest.java b/src/test/java/org/jabref/logic/util/VersionTest.java index 950bddb2c86..b2f90644b65 100644 --- a/src/test/java/org/jabref/logic/util/VersionTest.java +++ b/src/test/java/org/jabref/logic/util/VersionTest.java @@ -5,11 +5,11 @@ import java.util.List; import java.util.Optional; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; public class VersionTest { diff --git a/src/test/java/org/jabref/logic/util/io/FileHistoryTest.java b/src/test/java/org/jabref/logic/util/io/FileHistoryTest.java index 280d24630c2..715e461dee9 100644 --- a/src/test/java/org/jabref/logic/util/io/FileHistoryTest.java +++ b/src/test/java/org/jabref/logic/util/io/FileHistoryTest.java @@ -3,9 +3,9 @@ import java.util.ArrayList; import java.util.Arrays; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class FileHistoryTest { diff --git a/src/test/java/org/jabref/logic/util/io/FileNameCleanerTest.java b/src/test/java/org/jabref/logic/util/io/FileNameCleanerTest.java index cbd29d9b61a..fdb18565ca5 100644 --- a/src/test/java/org/jabref/logic/util/io/FileNameCleanerTest.java +++ b/src/test/java/org/jabref/logic/util/io/FileNameCleanerTest.java @@ -1,27 +1,28 @@ package org.jabref.logic.util.io; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; public class FileNameCleanerTest { @Test public void testCleanFileName() { - Assert.assertEquals("legalFilename.txt", FileNameCleaner.cleanFileName("legalFilename.txt")); - Assert.assertEquals("illegalFilename______.txt", FileNameCleaner.cleanFileName("illegalFilename/?*<>|.txt")); + assertEquals("legalFilename.txt", FileNameCleaner.cleanFileName("legalFilename.txt")); + assertEquals("illegalFilename______.txt", FileNameCleaner.cleanFileName("illegalFilename/?*<>|.txt")); } @Test public void testCleanDirectoryName() { - Assert.assertEquals("legalFilename.txt", FileNameCleaner.cleanDirectoryName("legalFilename.txt")); - Assert.assertEquals("subdir/legalFilename.txt", FileNameCleaner.cleanDirectoryName("subdir/legalFilename.txt")); - Assert.assertEquals("illegalFilename/_____.txt", FileNameCleaner.cleanDirectoryName("illegalFilename/?*<>|.txt")); + assertEquals("legalFilename.txt", FileNameCleaner.cleanDirectoryName("legalFilename.txt")); + assertEquals("subdir/legalFilename.txt", FileNameCleaner.cleanDirectoryName("subdir/legalFilename.txt")); + assertEquals("illegalFilename/_____.txt", FileNameCleaner.cleanDirectoryName("illegalFilename/?*<>|.txt")); } @Test public void testCleanDirectoryNameForWindows() { - Assert.assertEquals("legalFilename.txt", FileNameCleaner.cleanDirectoryName("legalFilename.txt")); - Assert.assertEquals("subdir\\legalFilename.txt", FileNameCleaner.cleanDirectoryName("subdir\\legalFilename.txt")); - Assert.assertEquals("illegalFilename\\_____.txt", FileNameCleaner.cleanDirectoryName("illegalFilename\\?*<>|.txt")); + assertEquals("legalFilename.txt", FileNameCleaner.cleanDirectoryName("legalFilename.txt")); + assertEquals("subdir\\legalFilename.txt", FileNameCleaner.cleanDirectoryName("subdir\\legalFilename.txt")); + assertEquals("illegalFilename\\_____.txt", FileNameCleaner.cleanDirectoryName("illegalFilename\\?*<>|.txt")); } } diff --git a/src/test/java/org/jabref/logic/util/io/RegExpBasedFileFinderTests.java b/src/test/java/org/jabref/logic/util/io/RegExpBasedFileFinderTests.java index c627eb0f438..b550ca52a2d 100644 --- a/src/test/java/org/jabref/logic/util/io/RegExpBasedFileFinderTests.java +++ b/src/test/java/org/jabref/logic/util/io/RegExpBasedFileFinderTests.java @@ -9,11 +9,11 @@ import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.BibtexEntryTypes; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; public class RegExpBasedFileFinderTests { @@ -21,7 +21,7 @@ public class RegExpBasedFileFinderTests { private BibDatabase database; private BibEntry entry; - @Before + @BeforeEach public void setUp() { entry = new BibEntry(); @@ -137,7 +137,7 @@ public void testFindFileNonRecursive() throws Exception { List result = fileFinder.findAssociatedFiles(localEntry, dirs, extensions); //then - Assert.assertTrue(result.isEmpty()); + assertTrue(result.isEmpty()); } @Test diff --git a/src/test/java/org/jabref/logic/util/strings/DiffHighlightingTest.java b/src/test/java/org/jabref/logic/util/strings/DiffHighlightingTest.java index fd1576f8a50..bda3faa126c 100644 --- a/src/test/java/org/jabref/logic/util/strings/DiffHighlightingTest.java +++ b/src/test/java/org/jabref/logic/util/strings/DiffHighlightingTest.java @@ -1,10 +1,10 @@ package org.jabref.logic.util.strings; -import org.junit.Test; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; public class DiffHighlightingTest { @@ -13,9 +13,9 @@ public void testGenerateDiffHighlightingBothNullReturnsNull() { assertNull(DiffHighlighting.generateDiffHighlighting(null, null, "")); } - @Test(expected = NullPointerException.class) + @Test public void testNullSeparatorThrowsNPE() { - assertNull(DiffHighlighting.generateDiffHighlighting("", "", null)); + assertThrows(NullPointerException.class, () -> DiffHighlighting.generateDiffHighlighting("", "", null)); } @Test diff --git a/src/test/java/org/jabref/logic/util/strings/StringLengthComparatorTest.java b/src/test/java/org/jabref/logic/util/strings/StringLengthComparatorTest.java index d4adf6358a8..3cfb74ea74f 100644 --- a/src/test/java/org/jabref/logic/util/strings/StringLengthComparatorTest.java +++ b/src/test/java/org/jabref/logic/util/strings/StringLengthComparatorTest.java @@ -1,10 +1,9 @@ package org.jabref.logic.util.strings; import org.junit.Before; -import org.junit.Test; - -import static org.junit.Assert.assertEquals; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; public class StringLengthComparatorTest { diff --git a/src/test/java/org/jabref/logic/xmp/XMPSchemaBibtexTest.java b/src/test/java/org/jabref/logic/xmp/XMPSchemaBibtexTest.java index 45413a0aa57..77e9548805e 100644 --- a/src/test/java/org/jabref/logic/xmp/XMPSchemaBibtexTest.java +++ b/src/test/java/org/jabref/logic/xmp/XMPSchemaBibtexTest.java @@ -17,33 +17,35 @@ import org.apache.jempbox.impl.XMLUtil; import org.apache.jempbox.xmp.XMPMetadata; -import org.junit.Assert; import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -@RunWith(MockitoJUnitRunner.class) public class XMPSchemaBibtexTest { - @Mock private ImportFormatPreferences prefs; + public void setUp() { + prefs = mock(ImportFormatPreferences.class); + } + public void assertEqualsBibtexEntry(BibEntry e, BibEntry x) { - Assert.assertNotNull(e); - Assert.assertNotNull(x); - Assert.assertEquals(e.getCiteKeyOptional(), x.getCiteKeyOptional()); - Assert.assertEquals(e.getType(), x.getType()); + assertNotNull(e); + assertNotNull(x); + assertEquals(e.getCiteKeyOptional(), x.getCiteKeyOptional()); + assertEquals(e.getType(), x.getType()); - Assert.assertEquals(e.getFieldNames().size(), x.getFieldNames().size()); + assertEquals(e.getFieldNames().size(), x.getFieldNames().size()); for (String name : e.getFieldNames()) { - Assert.assertEquals(e.getField(name), x.getField(name)); + assertEquals(e.getField(name), x.getField(name)); } } @@ -53,8 +55,8 @@ public void testXMPSchemaBibtexXMPMetadata() throws IOException { XMPMetadata xmp = new XMPMetadata(); XMPSchemaBibtex bibtex = new XMPSchemaBibtex(xmp); - Assert.assertNotNull(bibtex.getElement()); - Assert.assertEquals("rdf:Description", bibtex.getElement().getTagName()); + assertNotNull(bibtex.getElement()); + assertEquals("rdf:Description", bibtex.getElement().getTagName()); } @@ -68,8 +70,8 @@ public void testXMPSchemaBibtexElement() XMPSchemaBibtex bibtex = new XMPSchemaBibtex(e, "bibtex"); - Assert.assertEquals(e, bibtex.getElement()); - Assert.assertEquals("rdf:Description", bibtex.getElement().getTagName()); + assertEquals(e, bibtex.getElement()); + assertEquals("rdf:Description", bibtex.getElement().getTagName()); } @Test @@ -82,21 +84,21 @@ public void testGetSetPersonList() throws IOException { Element e = bibtex.getElement(); NodeList l1 = e.getElementsByTagName("bibtex:author"); - Assert.assertEquals(1, l1.getLength()); + assertEquals(1, l1.getLength()); NodeList l = e.getElementsByTagName("rdf:li"); - Assert.assertEquals(2, l.getLength()); + assertEquals(2, l.getLength()); - Assert.assertEquals("Tom DeMarco", XMLUtil + assertEquals("Tom DeMarco", XMLUtil .getStringValue((Element) l.item(0))); - Assert.assertEquals("Kent Beck", XMLUtil.getStringValue((Element) l.item(1))); + assertEquals("Kent Beck", XMLUtil.getStringValue((Element) l.item(1))); List authors = bibtex.getPersonList("author"); - Assert.assertEquals(2, authors.size()); + assertEquals(2, authors.size()); - Assert.assertEquals("Tom DeMarco", authors.get(0)); - Assert.assertEquals("Kent Beck", authors.get(1)); + assertEquals("Tom DeMarco", authors.get(0)); + assertEquals("Kent Beck", authors.get(1)); } @Test @@ -108,27 +110,27 @@ public void testSetGetTextPropertyString() throws IOException { "The advanced Flux-Compensation for Delawney-Separation"); Element e = bibtex.getElement(); - Assert.assertEquals("The advanced Flux-Compensation for Delawney-Separation", + assertEquals("The advanced Flux-Compensation for Delawney-Separation", e.getAttribute("bibtex:title")); - Assert.assertEquals("The advanced Flux-Compensation for Delawney-Separation", + assertEquals("The advanced Flux-Compensation for Delawney-Separation", bibtex.getTextProperty("title")); bibtex.setTextProperty("title", "The advanced Flux-Correlation for Delawney-Separation"); e = bibtex.getElement(); - Assert.assertEquals("The advanced Flux-Correlation for Delawney-Separation", e + assertEquals("The advanced Flux-Correlation for Delawney-Separation", e .getAttribute("bibtex:title")); - Assert.assertEquals("The advanced Flux-Correlation for Delawney-Separation", + assertEquals("The advanced Flux-Correlation for Delawney-Separation", bibtex.getTextProperty("title")); bibtex .setTextProperty( "abstract", " The abstract\n can go \n \n on several \n lines with \n many \n\n empty ones in \n between."); - Assert.assertEquals( + assertEquals( " The abstract\n can go \n \n on several \n lines with \n many \n\n empty ones in \n between.", bibtex.getTextProperty("abstract")); } @@ -145,36 +147,36 @@ public void testSetGetBagListString() throws IOException { List l = bibtex.getBagList("author"); - Assert.assertEquals(2, l.size()); + assertEquals(2, l.size()); - Assert.assertTrue(l.get(0).equals("Tom DeMarco") + assertTrue(l.get(0).equals("Tom DeMarco") || l.get(1).equals("Tom DeMarco")); - Assert.assertTrue(l.get(0).equals("Kent Beck") + assertTrue(l.get(0).equals("Kent Beck") || l.get(1).equals("Kent Beck")); } { bibtex.removeBagValue("author", "Kent Beck"); List l = bibtex.getBagList("author"); - Assert.assertEquals(1, l.size()); - Assert.assertTrue(l.get(0).equals("Tom DeMarco")); + assertEquals(1, l.size()); + assertTrue(l.get(0).equals("Tom DeMarco")); } { // Already removed bibtex.removeBagValue("author", "Kent Beck"); List l = bibtex.getBagList("author"); - Assert.assertEquals(1, l.size()); - Assert.assertTrue(l.get(0).equals("Tom DeMarco")); + assertEquals(1, l.size()); + assertTrue(l.get(0).equals("Tom DeMarco")); } { // Duplicates allowed! bibtex.addBagValue("author", "Tom DeMarco"); List l = bibtex.getBagList("author"); - Assert.assertEquals(2, l.size()); - Assert.assertTrue(l.get(0).equals("Tom DeMarco")); - Assert.assertTrue(l.get(1).equals("Tom DeMarco")); + assertEquals(2, l.size()); + assertTrue(l.get(0).equals("Tom DeMarco")); + assertTrue(l.get(1).equals("Tom DeMarco")); } // Removes both bibtex.removeBagValue("author", "Tom DeMarco"); List l = bibtex.getBagList("author"); - Assert.assertEquals(0, l.size()); + assertEquals(0, l.size()); } @Test @@ -189,34 +191,34 @@ public void testGetSequenceListString() throws IOException { List l = bibtex.getSequenceList("author"); - Assert.assertEquals(2, l.size()); + assertEquals(2, l.size()); - Assert.assertEquals("Tom DeMarco", l.get(0)); - Assert.assertEquals("Kent Beck", l.get(1)); + assertEquals("Tom DeMarco", l.get(0)); + assertEquals("Kent Beck", l.get(1)); } { bibtex.removeSequenceValue("author", "Tom DeMarco"); List l = bibtex.getSequenceList("author"); - Assert.assertEquals(1, l.size()); - Assert.assertTrue(l.get(0).equals("Kent Beck")); + assertEquals(1, l.size()); + assertTrue(l.get(0).equals("Kent Beck")); } { // Already removed bibtex.removeSequenceValue("author", "Tom DeMarco"); List l = bibtex.getSequenceList("author"); - Assert.assertEquals(1, l.size()); - Assert.assertTrue(l.get(0).equals("Kent Beck")); + assertEquals(1, l.size()); + assertTrue(l.get(0).equals("Kent Beck")); } { // Duplicates allowed! bibtex.addSequenceValue("author", "Kent Beck"); List l = bibtex.getSequenceList("author"); - Assert.assertEquals(2, l.size()); - Assert.assertTrue(l.get(0).equals("Kent Beck")); - Assert.assertTrue(l.get(1).equals("Kent Beck")); + assertEquals(2, l.size()); + assertTrue(l.get(0).equals("Kent Beck")); + assertTrue(l.get(1).equals("Kent Beck")); } // Remvoes all bibtex.removeSequenceValue("author", "Kent Beck"); List l = bibtex.getSequenceList("author"); - Assert.assertEquals(0, l.size()); + assertEquals(0, l.size()); } @Test @@ -233,15 +235,15 @@ public void testGetAllProperties() throws IOException { Map s = XMPSchemaBibtex.getAllProperties(bibtex, "bibtex"); - Assert.assertEquals(5, s.size()); - Assert.assertTrue(s.containsKey("title")); - Assert.assertTrue(s.containsKey("author")); + assertEquals(5, s.size()); + assertTrue(s.containsKey("title")); + assertTrue(s.containsKey("author")); - Assert.assertEquals("BlaBla Ta Ta Hello World", s.get("title")); - Assert.assertEquals("BlaBla Ta Ta\nHello World", s.get("abstract")); - Assert.assertEquals("BlaBla Ta Ta\nHello World", s.get("review")); - Assert.assertEquals("BlaBla Ta Ta\nHello World", s.get("note")); - Assert.assertEquals("Mickey Mouse and James Bond", s.get("author")); + assertEquals("BlaBla Ta Ta Hello World", s.get("title")); + assertEquals("BlaBla Ta Ta\nHello World", s.get("abstract")); + assertEquals("BlaBla Ta Ta\nHello World", s.get("review")); + assertEquals("BlaBla Ta Ta\nHello World", s.get("note")); + assertEquals("Mickey Mouse and James Bond", s.get("author")); } @Test @@ -272,7 +274,7 @@ public void testGetTextContent() throws IOException { Document d = XMLUtil.parse(new ByteArrayInputStream(bibtexString .getBytes(StandardCharsets.UTF_8))); - Assert.assertEquals("Beach sand convolution by surf-wave optimzation", + assertEquals("Beach sand convolution by surf-wave optimzation", XMPSchemaBibtex.getTextContent( d.getElementsByTagName("bibtex:title").item(0)).trim()); diff --git a/src/test/java/org/jabref/migrations/PreferencesMigrationsTest.java b/src/test/java/org/jabref/migrations/PreferencesMigrationsTest.java index 59f86305da8..78f2fd7b22d 100644 --- a/src/test/java/org/jabref/migrations/PreferencesMigrationsTest.java +++ b/src/test/java/org/jabref/migrations/PreferencesMigrationsTest.java @@ -6,10 +6,10 @@ import org.jabref.JabRefMain; import org.jabref.preferences.JabRefPreferences; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class PreferencesMigrationsTest { @@ -20,7 +20,7 @@ public class PreferencesMigrationsTest { private final String[] newStylePatterns = new String[] {"[bibtexkey]", "[bibtexkey] - [fulltitle]"}; - @Before + @BeforeEach public void setUp() { prefs = JabRefPreferences.getInstance(); Globals.prefs = prefs; diff --git a/src/test/java/org/jabref/model/BibDatabaseContextTest.java b/src/test/java/org/jabref/model/BibDatabaseContextTest.java index a15e7650e30..701833e223d 100644 --- a/src/test/java/org/jabref/model/BibDatabaseContextTest.java +++ b/src/test/java/org/jabref/model/BibDatabaseContextTest.java @@ -6,9 +6,9 @@ import org.jabref.model.entry.BibEntry; import org.jabref.model.metadata.MetaData; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class BibDatabaseContextTest { @Test diff --git a/src/test/java/org/jabref/model/database/BibDatabaseContextTest.java b/src/test/java/org/jabref/model/database/BibDatabaseContextTest.java index 0a944e5e4d3..fed023613b0 100644 --- a/src/test/java/org/jabref/model/database/BibDatabaseContextTest.java +++ b/src/test/java/org/jabref/model/database/BibDatabaseContextTest.java @@ -8,11 +8,9 @@ import org.jabref.model.metadata.FileDirectoryPreferences; import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -25,8 +23,6 @@ public class BibDatabaseContextTest { // FileDirectoryPreferences) incocation: private FileDirectoryPreferences fileDirPrefs; - @Rule public ExpectedException thrown = ExpectedException.none(); - @Before public void setUp() { fileDirPrefs = mock(FileDirectoryPreferences.class); diff --git a/src/test/java/org/jabref/model/database/BibDatabaseModeDetectionTest.java b/src/test/java/org/jabref/model/database/BibDatabaseModeDetectionTest.java index fe8609d904b..a157a4e3de9 100644 --- a/src/test/java/org/jabref/model/database/BibDatabaseModeDetectionTest.java +++ b/src/test/java/org/jabref/model/database/BibDatabaseModeDetectionTest.java @@ -9,9 +9,9 @@ import org.jabref.model.entry.BibtexEntryTypes; import org.jabref.model.entry.CustomEntryType; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class BibDatabaseModeDetectionTest { @Test diff --git a/src/test/java/org/jabref/model/database/DuplicationCheckerTest.java b/src/test/java/org/jabref/model/database/DuplicationCheckerTest.java index e9733e9f94e..e280a41d5c7 100644 --- a/src/test/java/org/jabref/model/database/DuplicationCheckerTest.java +++ b/src/test/java/org/jabref/model/database/DuplicationCheckerTest.java @@ -2,18 +2,17 @@ import org.jabref.model.entry.BibEntry; -import org.junit.Before; -import org.junit.Test; - -import static org.junit.Assert.assertEquals; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; public class DuplicationCheckerTest { private BibDatabase database; - @Before + @BeforeEach public void setUp() { database = new BibDatabase(); } diff --git a/src/test/java/org/jabref/model/database/KeyChangeListenerTest.java b/src/test/java/org/jabref/model/database/KeyChangeListenerTest.java index 137bb6ce896..2540b5ed75e 100644 --- a/src/test/java/org/jabref/model/database/KeyChangeListenerTest.java +++ b/src/test/java/org/jabref/model/database/KeyChangeListenerTest.java @@ -5,10 +5,10 @@ import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.FieldName; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class KeyChangeListenerTest { @@ -19,7 +19,7 @@ public class KeyChangeListenerTest { private BibEntry entry4; - @Before + @BeforeEach public void setUp() { db = new BibDatabase(); diff --git a/src/test/java/org/jabref/model/database/event/AutosaveEventTest.java b/src/test/java/org/jabref/model/database/event/AutosaveEventTest.java index 46821edc456..280a2b70c96 100644 --- a/src/test/java/org/jabref/model/database/event/AutosaveEventTest.java +++ b/src/test/java/org/jabref/model/database/event/AutosaveEventTest.java @@ -1,6 +1,6 @@ package org.jabref.model.database.event; -import org.junit.Test; +import org.junit.jupiter.api.Test; import static org.junit.Assert.assertNotNull; diff --git a/src/test/java/org/jabref/model/entry/AuthorTest.java b/src/test/java/org/jabref/model/entry/AuthorTest.java index 2d0f2cd6437..c5c40902927 100644 --- a/src/test/java/org/jabref/model/entry/AuthorTest.java +++ b/src/test/java/org/jabref/model/entry/AuthorTest.java @@ -1,8 +1,8 @@ package org.jabref.model.entry; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class AuthorTest { diff --git a/src/test/java/org/jabref/model/entry/BibEntryEqualityTest.java b/src/test/java/org/jabref/model/entry/BibEntryEqualityTest.java index 061dd189637..14550fe28df 100644 --- a/src/test/java/org/jabref/model/entry/BibEntryEqualityTest.java +++ b/src/test/java/org/jabref/model/entry/BibEntryEqualityTest.java @@ -1,9 +1,9 @@ package org.jabref.model.entry; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; public class BibEntryEqualityTest { @Test diff --git a/src/test/java/org/jabref/model/entry/BibEntryTest.java b/src/test/java/org/jabref/model/entry/BibEntryTest.java index 5cbea9d9477..48f9b649f31 100644 --- a/src/test/java/org/jabref/model/entry/BibEntryTest.java +++ b/src/test/java/org/jabref/model/entry/BibEntryTest.java @@ -6,35 +6,36 @@ import org.jabref.model.database.BibDatabase; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; public class BibEntryTest { private BibEntry entry; - @Before + @BeforeEach public void setUp() { entry = new BibEntry(); } - @After + @AfterEach public void tearDown() { entry = null; } - @Test(expected = IllegalArgumentException.class) + @Test public void notOverrideReservedFields() { - entry.setField(BibEntry.ID_FIELD, "somevalue"); + assertThrows(IllegalArgumentException.class, () -> entry.setField(BibEntry.ID_FIELD, "somevalue")); } - @Test(expected = IllegalArgumentException.class) + @Test public void notClearReservedFields() { - entry.clearField(BibEntry.ID_FIELD); + assertThrows(IllegalArgumentException.class, () -> entry.clearField(BibEntry.ID_FIELD)); } @Test diff --git a/src/test/java/org/jabref/model/entry/BibEntryTests.java b/src/test/java/org/jabref/model/entry/BibEntryTests.java index c4bd826a453..eb6b414225f 100644 --- a/src/test/java/org/jabref/model/entry/BibEntryTests.java +++ b/src/test/java/org/jabref/model/entry/BibEntryTests.java @@ -6,26 +6,25 @@ import java.util.List; import java.util.Optional; -import com.google.common.collect.Sets; import org.jabref.model.FieldChange; - import org.jabref.model.entry.specialfields.SpecialField; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import com.google.common.collect.Sets; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; public class BibEntryTests { private BibEntry keywordEntry; private BibEntry emptyEntry; - - - @Before + @BeforeEach public void setUp() { // Default entry for most keyword and some type tests keywordEntry = new BibEntry(); @@ -45,8 +44,8 @@ public void testDefaultConstructor() { BibEntry entry = new BibEntry(); // we have to use `getType("misc")` in the case of biblatex mode assertEquals("misc", entry.getType()); - Assert.assertNotNull(entry.getId()); - Assert.assertFalse(entry.getField("author").isPresent()); + assertNotNull(entry.getId()); + assertFalse(entry.getField("author").isPresent()); } @Test @@ -59,10 +58,10 @@ public void allFieldsPresentDefault() { requiredFields.add("author"); requiredFields.add("title"); - Assert.assertTrue(e.allFieldsPresent(requiredFields, null)); + assertTrue(e.allFieldsPresent(requiredFields, null)); requiredFields.add("year"); - Assert.assertFalse(e.allFieldsPresent(requiredFields, null)); + assertFalse(e.allFieldsPresent(requiredFields, null)); } @Test @@ -75,33 +74,31 @@ public void allFieldsPresentOr() { // XOR required requiredFields.add("journal/year"); - Assert.assertTrue(e.allFieldsPresent(requiredFields, null)); + assertTrue(e.allFieldsPresent(requiredFields, null)); requiredFields.add("year/address"); - Assert.assertFalse(e.allFieldsPresent(requiredFields, null)); + assertFalse(e.allFieldsPresent(requiredFields, null)); } - @Test(expected = NullPointerException.class) + @Test public void isNullCiteKeyThrowsNPE() { BibEntry e = new BibEntry(BibtexEntryTypes.ARTICLE.getName()); - - e.setCiteKey(null); - Assert.fail(); + assertThrows(NullPointerException.class, () -> e.setCiteKey(null)); } @Test public void isEmptyCiteKey() { BibEntry e = new BibEntry(BibtexEntryTypes.ARTICLE.getName()); - Assert.assertFalse(e.hasCiteKey()); + assertFalse(e.hasCiteKey()); e.setCiteKey(""); - Assert.assertFalse(e.hasCiteKey()); + assertFalse(e.hasCiteKey()); e.setCiteKey("key"); - Assert.assertTrue(e.hasCiteKey()); + assertTrue(e.hasCiteKey()); e.clearField(BibEntry.KEY_FIELD); - Assert.assertFalse(e.hasCiteKey()); + assertFalse(e.hasCiteKey()); } @Test @@ -118,7 +115,6 @@ public void typeOfBibEntryIsMiscAfterSettingToEmptyString() { assertEquals("misc", keywordEntry.getType()); } - @Test public void getFieldOrAliasDateWithYearNumericalMonthString() { emptyEntry.setField("year", "2003"); @@ -212,28 +208,28 @@ public void getFieldOrAliasLatexFreeComplexConversionInAlias() { assertEquals(Optional.of("A 32 mA ΣΔ-modulator"), emptyEntry.getFieldOrAliasLatexFree("journaltitle")); } - @Test(expected = NullPointerException.class) + @Test public void setNullField() { - emptyEntry.setField(null); - Assert.fail(); + assertThrows(NullPointerException.class, () -> emptyEntry.setField(null)); + } - @Test(expected = NullPointerException.class) + @Test public void addNullKeywordThrowsNPE() { - keywordEntry.addKeyword((Keyword)null, ','); - Assert.fail(); + assertThrows(NullPointerException.class, () -> keywordEntry.addKeyword((Keyword) null, ',')); } - @Test(expected = NullPointerException.class) + @Test public void putNullKeywordListThrowsNPE() { - keywordEntry.putKeywords((KeywordList)null, ','); - Assert.fail(); + assertThrows(NullPointerException.class, () -> keywordEntry.putKeywords((KeywordList) null, ',')); + } - @Test(expected = NullPointerException.class) + @Test public void putNullKeywordSeparatorThrowsNPE() { - keywordEntry.putKeywords(Arrays.asList("A", "B"), null); + assertThrows(NullPointerException.class, () -> keywordEntry.putKeywords(Arrays.asList("A", "B"), null)); } + @Test public void testGetSeparatedKeywordsAreCorrect() { assertEquals(new KeywordList("Foo", "Bar"), keywordEntry.getKeywords(',')); @@ -248,7 +244,7 @@ public void testAddKeywordIsCorrect() { @Test public void testAddKeywordHasChanged() { keywordEntry.addKeyword("FooBar", ','); - Assert.assertTrue(keywordEntry.hasChanged()); + assertTrue(keywordEntry.hasChanged()); } @Test @@ -267,7 +263,7 @@ public void addKeywordIsCaseSensitive() { @Test public void testAddKeywordWithDifferentCapitalizationChanges() { keywordEntry.addKeyword("FOO", ','); - Assert.assertTrue(keywordEntry.hasChanged()); + assertTrue(keywordEntry.hasChanged()); } @Test @@ -279,24 +275,24 @@ public void testAddKeywordEmptyKeywordIsNotAdded() { @Test public void testAddKeywordEmptyKeywordNotChanged() { keywordEntry.addKeyword("", ','); - Assert.assertFalse(keywordEntry.hasChanged()); + assertFalse(keywordEntry.hasChanged()); } @Test public void texNewBibEntryHasNoKeywords() { - Assert.assertTrue(emptyEntry.getKeywords(',').isEmpty()); + assertTrue(emptyEntry.getKeywords(',').isEmpty()); } @Test public void texNewBibEntryHasNoKeywordsEvenAfterAddingEmptyKeyword() { emptyEntry.addKeyword("", ','); - Assert.assertTrue(emptyEntry.getKeywords(',').isEmpty()); + assertTrue(emptyEntry.getKeywords(',').isEmpty()); } @Test public void texNewBibEntryAfterAddingEmptyKeywordNotChanged() { emptyEntry.addKeyword("", ','); - Assert.assertFalse(emptyEntry.hasChanged()); + assertFalse(emptyEntry.hasChanged()); } @Test @@ -314,31 +310,31 @@ public void testPutKeywordsOverwritesOldKeywords() { @Test public void testPutKeywordsHasChanged() { keywordEntry.putKeywords(Arrays.asList("Yin", "Yang"), ','); - Assert.assertTrue(keywordEntry.hasChanged()); + assertTrue(keywordEntry.hasChanged()); } @Test public void testPutKeywordsPutEmpyListErasesPreviousKeywords() { keywordEntry.putKeywords(Collections.emptyList(), ','); - Assert.assertTrue(keywordEntry.getKeywords(',').isEmpty()); + assertTrue(keywordEntry.getKeywords(',').isEmpty()); } @Test public void testPutKeywordsPutEmpyListHasChanged() { keywordEntry.putKeywords(Collections.emptyList(), ','); - Assert.assertTrue(keywordEntry.hasChanged()); + assertTrue(keywordEntry.hasChanged()); } @Test public void testPutKeywordsPutEmpyListToEmptyBibentry() { emptyEntry.putKeywords(Collections.emptyList(), ','); - Assert.assertTrue(emptyEntry.getKeywords(',').isEmpty()); + assertTrue(emptyEntry.getKeywords(',').isEmpty()); } @Test public void testPutKeywordsPutEmpyListToEmptyBibentryNotChanged() { emptyEntry.putKeywords(Collections.emptyList(), ','); - Assert.assertFalse(emptyEntry.hasChanged()); + assertFalse(emptyEntry.hasChanged()); } @Test @@ -407,23 +403,23 @@ public void removeKeywordsWithExistingKeywordsRemovesThem() { public void testGroupAndSearchHits() { BibEntry be = new BibEntry(); be.setGroupHit(true); - Assert.assertTrue(be.isGroupHit()); + assertTrue(be.isGroupHit()); be.setGroupHit(false); - Assert.assertFalse(be.isGroupHit()); + assertFalse(be.isGroupHit()); be.setSearchHit(true); - Assert.assertTrue(be.isSearchHit()); + assertTrue(be.isSearchHit()); be.setSearchHit(false); - Assert.assertFalse(be.isSearchHit()); + assertFalse(be.isSearchHit()); } @Test public void setCiteKey() { BibEntry be = new BibEntry(); - Assert.assertFalse(be.hasCiteKey()); + assertFalse(be.hasCiteKey()); be.setField("author", "Albert Einstein"); be.setCiteKey("Einstein1931"); - Assert.assertTrue(be.hasCiteKey()); + assertTrue(be.hasCiteKey()); assertEquals(Optional.of("Einstein1931"), be.getCiteKeyOptional()); assertEquals(Optional.of("Albert Einstein"), be.getField("author")); be.clearField("author"); diff --git a/src/test/java/org/jabref/model/entry/BibtexStringTest.java b/src/test/java/org/jabref/model/entry/BibtexStringTest.java index 397746fc893..440c950394d 100644 --- a/src/test/java/org/jabref/model/entry/BibtexStringTest.java +++ b/src/test/java/org/jabref/model/entry/BibtexStringTest.java @@ -1,11 +1,10 @@ package org.jabref.model.entry; -import org.junit.Test; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertNotNull; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; public class BibtexStringTest { diff --git a/src/test/java/org/jabref/model/entry/CanonicalBibEntryTest.java b/src/test/java/org/jabref/model/entry/CanonicalBibEntryTest.java index 8788761e387..cb1a79ad172 100644 --- a/src/test/java/org/jabref/model/entry/CanonicalBibEntryTest.java +++ b/src/test/java/org/jabref/model/entry/CanonicalBibEntryTest.java @@ -1,7 +1,8 @@ package org.jabref.model.entry; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; public class CanonicalBibEntryTest { @@ -13,7 +14,7 @@ public void simpleCanonicalRepresentation() { e.setField("title", "def"); e.setField("journal", "hij"); String canonicalRepresentation = CanonicalBibtexEntry.getCanonicalRepresentation(e); - Assert.assertEquals("@article{key,\n author = {abc},\n journal = {hij},\n title = {def}\n}", + assertEquals("@article{key,\n author = {abc},\n journal = {hij},\n title = {def}\n}", canonicalRepresentation); } @@ -23,7 +24,7 @@ public void canonicalRepresentationWithNewlines() { e.setCiteKey("key"); e.setField("abstract", "line 1\nline 2"); String canonicalRepresentation = CanonicalBibtexEntry.getCanonicalRepresentation(e); - Assert.assertEquals("@article{key,\n abstract = {line 1\nline 2}\n}", canonicalRepresentation); + assertEquals("@article{key,\n abstract = {line 1\nline 2}\n}", canonicalRepresentation); } } diff --git a/src/test/java/org/jabref/model/entry/DateTest.java b/src/test/java/org/jabref/model/entry/DateTest.java index 3192ef78554..3234ea84280 100644 --- a/src/test/java/org/jabref/model/entry/DateTest.java +++ b/src/test/java/org/jabref/model/entry/DateTest.java @@ -3,9 +3,10 @@ import java.time.LocalDate; import java.util.Optional; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; public class DateTest { @@ -15,8 +16,7 @@ public void parseCorrectlyDayMonthYearDate() throws Exception { assertEquals(Optional.of(expected), Date.parse("19-06-2014")); } - @Test(expected = NullPointerException.class) public void parseDateNull() { - assertEquals(Optional.empty(), Date.parse(null)); + assertThrows(NullPointerException.class, () -> assertEquals(Optional.empty(), Date.parse(null))); } } diff --git a/src/test/java/org/jabref/model/entry/EntryLinkListTest.java b/src/test/java/org/jabref/model/entry/EntryLinkListTest.java index dba0cfb9c45..b1381b23fe9 100644 --- a/src/test/java/org/jabref/model/entry/EntryLinkListTest.java +++ b/src/test/java/org/jabref/model/entry/EntryLinkListTest.java @@ -1,14 +1,15 @@ package org.jabref.model.entry; -import org.jabref.model.database.BibDatabase; -import org.junit.Before; -import org.junit.Test; - import java.util.List; import java.util.Optional; -import static junit.framework.TestCase.assertTrue; +import org.jabref.model.database.BibDatabase; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; public class EntryLinkListTest { @@ -20,7 +21,7 @@ public class EntryLinkListTest { private BibEntry source; private BibEntry target; - @Before + @BeforeEach public void before() { database = new BibDatabase(); links = EntryLinkList.parse(key, database); diff --git a/src/test/java/org/jabref/model/entry/FieldNameTest.java b/src/test/java/org/jabref/model/entry/FieldNameTest.java index 393c159430b..b390886e1f5 100644 --- a/src/test/java/org/jabref/model/entry/FieldNameTest.java +++ b/src/test/java/org/jabref/model/entry/FieldNameTest.java @@ -2,8 +2,7 @@ import org.junit.Test; -import static org.junit.Assert.assertEquals; - +import static org.junit.jupiter.api.Assertions.assertEquals; public class FieldNameTest { diff --git a/src/test/java/org/jabref/model/entry/FileFieldBibEntryTest.java b/src/test/java/org/jabref/model/entry/FileFieldBibEntryTest.java index 54699f411da..c6505dc437d 100644 --- a/src/test/java/org/jabref/model/entry/FileFieldBibEntryTest.java +++ b/src/test/java/org/jabref/model/entry/FileFieldBibEntryTest.java @@ -10,16 +10,16 @@ import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.metadata.MetaData; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class FileFieldBibEntryTest { private BibEntry emptyEntry; - @Before + @BeforeEach public void setUp() { emptyEntry = new BibEntry(); emptyEntry.setType("article"); diff --git a/src/test/java/org/jabref/model/entry/FileFieldWriterTest.java b/src/test/java/org/jabref/model/entry/FileFieldWriterTest.java index 5929dd664a3..d9b6fb0f1e7 100644 --- a/src/test/java/org/jabref/model/entry/FileFieldWriterTest.java +++ b/src/test/java/org/jabref/model/entry/FileFieldWriterTest.java @@ -3,10 +3,10 @@ import java.util.Arrays; import java.util.Collections; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; public class FileFieldWriterTest { diff --git a/src/test/java/org/jabref/model/entry/IEEETranEntryTypesTest.java b/src/test/java/org/jabref/model/entry/IEEETranEntryTypesTest.java index 6767031e6a0..6d87b4bfcfb 100644 --- a/src/test/java/org/jabref/model/entry/IEEETranEntryTypesTest.java +++ b/src/test/java/org/jabref/model/entry/IEEETranEntryTypesTest.java @@ -3,8 +3,9 @@ import java.util.Collection; import java.util.List; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertTrue; public class IEEETranEntryTypesTest { @@ -13,7 +14,7 @@ public void ctlTypeContainsYesNoFields() { Collection ctlFields = IEEETranEntryTypes.IEEETRANBSTCTL.getAllFields(); List ynFields = InternalBibtexFields.getIEEETranBSTctlYesNoFields(); - Assert.assertTrue(ctlFields.containsAll(ynFields)); + assertTrue(ctlFields.containsAll(ynFields)); } } diff --git a/src/test/java/org/jabref/model/entry/IdGeneratorTest.java b/src/test/java/org/jabref/model/entry/IdGeneratorTest.java index 689f75e985e..f49e00b11c1 100644 --- a/src/test/java/org/jabref/model/entry/IdGeneratorTest.java +++ b/src/test/java/org/jabref/model/entry/IdGeneratorTest.java @@ -2,8 +2,9 @@ import java.util.HashSet; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertFalse; public class IdGeneratorTest { @@ -13,7 +14,7 @@ public void testCreateNeutralId() { HashSet set = new HashSet<>(); for (int i = 0; i < 10000; i++) { String string = IdGenerator.next(); - Assert.assertFalse(set.contains(string)); + assertFalse(set.contains(string)); set.add(string); } diff --git a/src/test/java/org/jabref/model/entry/KeywordListTest.java b/src/test/java/org/jabref/model/entry/KeywordListTest.java index 177d26f5940..8edcb36c07d 100644 --- a/src/test/java/org/jabref/model/entry/KeywordListTest.java +++ b/src/test/java/org/jabref/model/entry/KeywordListTest.java @@ -3,9 +3,9 @@ import java.util.Optional; import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class KeywordListTest { diff --git a/src/test/java/org/jabref/model/entry/KeywordTest.java b/src/test/java/org/jabref/model/entry/KeywordTest.java index 43f3a642028..a5047fa07a9 100644 --- a/src/test/java/org/jabref/model/entry/KeywordTest.java +++ b/src/test/java/org/jabref/model/entry/KeywordTest.java @@ -3,7 +3,7 @@ import java.util.HashSet; import java.util.Set; -import org.junit.Test; +import org.junit.jupiter.api.Test; import static org.junit.Assert.assertEquals; diff --git a/src/test/java/org/jabref/model/entry/MonthTest.java b/src/test/java/org/jabref/model/entry/MonthTest.java index 943f29fbf1b..dc5a29c8c26 100644 --- a/src/test/java/org/jabref/model/entry/MonthTest.java +++ b/src/test/java/org/jabref/model/entry/MonthTest.java @@ -2,101 +2,102 @@ import java.util.Optional; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; public class MonthTest { @Test public void parseCorrectlyByShortName() { - Assert.assertEquals(Optional.of(Month.JANUARY), Month.parse("jan")); - Assert.assertEquals(Optional.of(Month.FEBRUARY), Month.parse("feb")); - Assert.assertEquals(Optional.of(Month.MARCH), Month.parse("mar")); - Assert.assertEquals(Optional.of(Month.APRIL), Month.parse("apr")); - Assert.assertEquals(Optional.of(Month.MAY), Month.parse("may")); - Assert.assertEquals(Optional.of(Month.JUNE), Month.parse("jun")); - Assert.assertEquals(Optional.of(Month.JULY), Month.parse("jul")); - Assert.assertEquals(Optional.of(Month.AUGUST), Month.parse("aug")); - Assert.assertEquals(Optional.of(Month.SEPTEMBER), Month.parse("sep")); - Assert.assertEquals(Optional.of(Month.OCTOBER), Month.parse("oct")); - Assert.assertEquals(Optional.of(Month.NOVEMBER), Month.parse("nov")); - Assert.assertEquals(Optional.of(Month.DECEMBER), Month.parse("dec")); + assertEquals(Optional.of(Month.JANUARY), Month.parse("jan")); + assertEquals(Optional.of(Month.FEBRUARY), Month.parse("feb")); + assertEquals(Optional.of(Month.MARCH), Month.parse("mar")); + assertEquals(Optional.of(Month.APRIL), Month.parse("apr")); + assertEquals(Optional.of(Month.MAY), Month.parse("may")); + assertEquals(Optional.of(Month.JUNE), Month.parse("jun")); + assertEquals(Optional.of(Month.JULY), Month.parse("jul")); + assertEquals(Optional.of(Month.AUGUST), Month.parse("aug")); + assertEquals(Optional.of(Month.SEPTEMBER), Month.parse("sep")); + assertEquals(Optional.of(Month.OCTOBER), Month.parse("oct")); + assertEquals(Optional.of(Month.NOVEMBER), Month.parse("nov")); + assertEquals(Optional.of(Month.DECEMBER), Month.parse("dec")); } @Test public void parseCorrectlyByBibtexName() { - Assert.assertEquals(Optional.of(Month.JANUARY), Month.parse("#jan#")); - Assert.assertEquals(Optional.of(Month.FEBRUARY), Month.parse("#feb#")); - Assert.assertEquals(Optional.of(Month.MARCH), Month.parse("#mar#")); - Assert.assertEquals(Optional.of(Month.APRIL), Month.parse("#apr#")); - Assert.assertEquals(Optional.of(Month.MAY), Month.parse("#may#")); - Assert.assertEquals(Optional.of(Month.JUNE), Month.parse("#jun#")); - Assert.assertEquals(Optional.of(Month.JULY), Month.parse("#jul#")); - Assert.assertEquals(Optional.of(Month.AUGUST), Month.parse("#aug#")); - Assert.assertEquals(Optional.of(Month.SEPTEMBER), Month.parse("#sep#")); - Assert.assertEquals(Optional.of(Month.OCTOBER), Month.parse("#oct#")); - Assert.assertEquals(Optional.of(Month.NOVEMBER), Month.parse("#nov#")); - Assert.assertEquals(Optional.of(Month.DECEMBER), Month.parse("#dec#")); + assertEquals(Optional.of(Month.JANUARY), Month.parse("#jan#")); + assertEquals(Optional.of(Month.FEBRUARY), Month.parse("#feb#")); + assertEquals(Optional.of(Month.MARCH), Month.parse("#mar#")); + assertEquals(Optional.of(Month.APRIL), Month.parse("#apr#")); + assertEquals(Optional.of(Month.MAY), Month.parse("#may#")); + assertEquals(Optional.of(Month.JUNE), Month.parse("#jun#")); + assertEquals(Optional.of(Month.JULY), Month.parse("#jul#")); + assertEquals(Optional.of(Month.AUGUST), Month.parse("#aug#")); + assertEquals(Optional.of(Month.SEPTEMBER), Month.parse("#sep#")); + assertEquals(Optional.of(Month.OCTOBER), Month.parse("#oct#")); + assertEquals(Optional.of(Month.NOVEMBER), Month.parse("#nov#")); + assertEquals(Optional.of(Month.DECEMBER), Month.parse("#dec#")); } @Test public void parseCorrectlyByFullName() { - Assert.assertEquals(Optional.of(Month.JANUARY), Month.parse("January")); - Assert.assertEquals(Optional.of(Month.FEBRUARY), Month.parse("February")); - Assert.assertEquals(Optional.of(Month.MARCH), Month.parse("March")); - Assert.assertEquals(Optional.of(Month.APRIL), Month.parse("April")); - Assert.assertEquals(Optional.of(Month.MAY), Month.parse("May")); - Assert.assertEquals(Optional.of(Month.JUNE), Month.parse("June")); - Assert.assertEquals(Optional.of(Month.JULY), Month.parse("July")); - Assert.assertEquals(Optional.of(Month.AUGUST), Month.parse("August")); - Assert.assertEquals(Optional.of(Month.SEPTEMBER), Month.parse("September")); - Assert.assertEquals(Optional.of(Month.OCTOBER), Month.parse("October")); - Assert.assertEquals(Optional.of(Month.NOVEMBER), Month.parse("November")); - Assert.assertEquals(Optional.of(Month.DECEMBER), Month.parse("December")); + assertEquals(Optional.of(Month.JANUARY), Month.parse("January")); + assertEquals(Optional.of(Month.FEBRUARY), Month.parse("February")); + assertEquals(Optional.of(Month.MARCH), Month.parse("March")); + assertEquals(Optional.of(Month.APRIL), Month.parse("April")); + assertEquals(Optional.of(Month.MAY), Month.parse("May")); + assertEquals(Optional.of(Month.JUNE), Month.parse("June")); + assertEquals(Optional.of(Month.JULY), Month.parse("July")); + assertEquals(Optional.of(Month.AUGUST), Month.parse("August")); + assertEquals(Optional.of(Month.SEPTEMBER), Month.parse("September")); + assertEquals(Optional.of(Month.OCTOBER), Month.parse("October")); + assertEquals(Optional.of(Month.NOVEMBER), Month.parse("November")); + assertEquals(Optional.of(Month.DECEMBER), Month.parse("December")); } @Test public void parseCorrectlyByTwoDigitNumber() { - Assert.assertEquals(Optional.of(Month.JANUARY), Month.parse("01")); - Assert.assertEquals(Optional.of(Month.FEBRUARY), Month.parse("02")); - Assert.assertEquals(Optional.of(Month.MARCH), Month.parse("03")); - Assert.assertEquals(Optional.of(Month.APRIL), Month.parse("04")); - Assert.assertEquals(Optional.of(Month.MAY), Month.parse("05")); - Assert.assertEquals(Optional.of(Month.JUNE), Month.parse("06")); - Assert.assertEquals(Optional.of(Month.JULY), Month.parse("07")); - Assert.assertEquals(Optional.of(Month.AUGUST), Month.parse("08")); - Assert.assertEquals(Optional.of(Month.SEPTEMBER), Month.parse("09")); - Assert.assertEquals(Optional.of(Month.OCTOBER), Month.parse("10")); - Assert.assertEquals(Optional.of(Month.NOVEMBER), Month.parse("11")); - Assert.assertEquals(Optional.of(Month.DECEMBER), Month.parse("12")); + assertEquals(Optional.of(Month.JANUARY), Month.parse("01")); + assertEquals(Optional.of(Month.FEBRUARY), Month.parse("02")); + assertEquals(Optional.of(Month.MARCH), Month.parse("03")); + assertEquals(Optional.of(Month.APRIL), Month.parse("04")); + assertEquals(Optional.of(Month.MAY), Month.parse("05")); + assertEquals(Optional.of(Month.JUNE), Month.parse("06")); + assertEquals(Optional.of(Month.JULY), Month.parse("07")); + assertEquals(Optional.of(Month.AUGUST), Month.parse("08")); + assertEquals(Optional.of(Month.SEPTEMBER), Month.parse("09")); + assertEquals(Optional.of(Month.OCTOBER), Month.parse("10")); + assertEquals(Optional.of(Month.NOVEMBER), Month.parse("11")); + assertEquals(Optional.of(Month.DECEMBER), Month.parse("12")); } @Test public void parseCorrectlyByNumber() { - Assert.assertEquals(Optional.of(Month.JANUARY), Month.parse("1")); - Assert.assertEquals(Optional.of(Month.FEBRUARY), Month.parse("2")); - Assert.assertEquals(Optional.of(Month.MARCH), Month.parse("3")); - Assert.assertEquals(Optional.of(Month.APRIL), Month.parse("4")); - Assert.assertEquals(Optional.of(Month.MAY), Month.parse("5")); - Assert.assertEquals(Optional.of(Month.JUNE), Month.parse("6")); - Assert.assertEquals(Optional.of(Month.JULY), Month.parse("7")); - Assert.assertEquals(Optional.of(Month.AUGUST), Month.parse("8")); - Assert.assertEquals(Optional.of(Month.SEPTEMBER), Month.parse("9")); - Assert.assertEquals(Optional.of(Month.OCTOBER), Month.parse("10")); - Assert.assertEquals(Optional.of(Month.NOVEMBER), Month.parse("11")); - Assert.assertEquals(Optional.of(Month.DECEMBER), Month.parse("12")); + assertEquals(Optional.of(Month.JANUARY), Month.parse("1")); + assertEquals(Optional.of(Month.FEBRUARY), Month.parse("2")); + assertEquals(Optional.of(Month.MARCH), Month.parse("3")); + assertEquals(Optional.of(Month.APRIL), Month.parse("4")); + assertEquals(Optional.of(Month.MAY), Month.parse("5")); + assertEquals(Optional.of(Month.JUNE), Month.parse("6")); + assertEquals(Optional.of(Month.JULY), Month.parse("7")); + assertEquals(Optional.of(Month.AUGUST), Month.parse("8")); + assertEquals(Optional.of(Month.SEPTEMBER), Month.parse("9")); + assertEquals(Optional.of(Month.OCTOBER), Month.parse("10")); + assertEquals(Optional.of(Month.NOVEMBER), Month.parse("11")); + assertEquals(Optional.of(Month.DECEMBER), Month.parse("12")); } @Test public void parseReturnsEmptyOptionalForInvalidInput() { - Assert.assertEquals(Optional.empty(), Month.parse(";lkjasdf")); - Assert.assertEquals(Optional.empty(), Month.parse("3.2")); - Assert.assertEquals(Optional.empty(), Month.parse("#test#")); - Assert.assertEquals(Optional.empty(), Month.parse("8,")); + assertEquals(Optional.empty(), Month.parse(";lkjasdf")); + assertEquals(Optional.empty(), Month.parse("3.2")); + assertEquals(Optional.empty(), Month.parse("#test#")); + assertEquals(Optional.empty(), Month.parse("8,")); } @Test public void parseReturnsEmptyOptionalForEmptyInput() { - Assert.assertEquals(Optional.empty(), Month.parse("")); + assertEquals(Optional.empty(), Month.parse("")); } } diff --git a/src/test/java/org/jabref/model/entry/identifier/ArXivIdentifierTest.java b/src/test/java/org/jabref/model/entry/identifier/ArXivIdentifierTest.java index dbc8beda996..3109f4b3c76 100644 --- a/src/test/java/org/jabref/model/entry/identifier/ArXivIdentifierTest.java +++ b/src/test/java/org/jabref/model/entry/identifier/ArXivIdentifierTest.java @@ -2,9 +2,9 @@ import java.util.Optional; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class ArXivIdentifierTest { diff --git a/src/test/java/org/jabref/model/entry/identifier/DOITest.java b/src/test/java/org/jabref/model/entry/identifier/DOITest.java index d6db25c4278..457b779ff75 100644 --- a/src/test/java/org/jabref/model/entry/identifier/DOITest.java +++ b/src/test/java/org/jabref/model/entry/identifier/DOITest.java @@ -2,86 +2,88 @@ import java.util.Optional; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; public class DOITest { @Test public void acceptPlainDoi() { - Assert.assertEquals("10.1006/jmbi.1998.2354", new DOI("10.1006/jmbi.1998.2354").getDOI()); - Assert.assertEquals("10.231/JIM.0b013e31820bab4c", new DOI("10.231/JIM.0b013e31820bab4c").getDOI()); - Assert.assertEquals("10.1002/(SICI)1522-2594(199911)42:5<952::AID-MRM16>3.0.CO;2-S", + assertEquals("10.1006/jmbi.1998.2354", new DOI("10.1006/jmbi.1998.2354").getDOI()); + assertEquals("10.231/JIM.0b013e31820bab4c", new DOI("10.231/JIM.0b013e31820bab4c").getDOI()); + assertEquals("10.1002/(SICI)1522-2594(199911)42:5<952::AID-MRM16>3.0.CO;2-S", new DOI("10.1002/(SICI)1522-2594(199911)42:5<952::AID-MRM16>3.0.CO;2-S").getDOI()); - Assert.assertEquals("10.1126/sciadv.1500214", new DOI("10.1126/sciadv.1500214").getDOI()); + assertEquals("10.1126/sciadv.1500214", new DOI("10.1126/sciadv.1500214").getDOI()); } @Test public void ignoreLeadingAndTrailingWhitespaces() { - Assert.assertEquals("10.1006/jmbi.1998.2354", new DOI(" 10.1006/jmbi.1998.2354 ").getDOI()); + assertEquals("10.1006/jmbi.1998.2354", new DOI(" 10.1006/jmbi.1998.2354 ").getDOI()); } - @Test(expected = IllegalArgumentException.class) + @Test public void rejectEmbeddedDoi() { - new DOI("other stuff 10.1006/jmbi.1998.2354 end"); + assertThrows(IllegalArgumentException.class, () -> new DOI("other stuff 10.1006/jmbi.1998.2354 end")); } - @Test(expected = IllegalArgumentException.class) + @Test public void rejectInvalidDirectoryIndicator() { // wrong directory indicator - new DOI("12.1006/jmbi.1998.2354 end"); + assertThrows(IllegalArgumentException.class, () -> new DOI("12.1006/jmbi.1998.2354 end")); } - @Test(expected = IllegalArgumentException.class) + @Test public void rejectInvalidDoiUri() { - new DOI("https://thisisnouri"); + assertThrows(IllegalArgumentException.class, () -> new DOI("https://thisisnouri")); } - @Test(expected = IllegalArgumentException.class) + @Test public void rejectMissingDivider() { // missing divider - new DOI("10.1006jmbi.1998.2354 end"); + assertThrows(IllegalArgumentException.class, () -> new DOI("10.1006jmbi.1998.2354 end")); } @Test public void acceptDoiPrefix() { // Doi prefix - Assert.assertEquals("10.1006/jmbi.1998.2354", new DOI("doi:10.1006/jmbi.1998.2354").getDOI()); + assertEquals("10.1006/jmbi.1998.2354", new DOI("doi:10.1006/jmbi.1998.2354").getDOI()); } @Test public void acceptURNPrefix() { - Assert.assertEquals("10.123/456", new DOI("urn:10.123/456").getDOI()); - Assert.assertEquals("10.123/456", new DOI("urn:doi:10.123/456").getDOI()); - Assert.assertEquals("10.123/456", new DOI("http://doi.org/urn:doi:10.123/456").getDOI()); + assertEquals("10.123/456", new DOI("urn:10.123/456").getDOI()); + assertEquals("10.123/456", new DOI("urn:doi:10.123/456").getDOI()); + assertEquals("10.123/456", new DOI("http://doi.org/urn:doi:10.123/456").getDOI()); // : is also allowed as divider, will be replaced by RESOLVER - Assert.assertEquals("10.123:456ABC/zyz", new DOI("http://doi.org/urn:doi:10.123:456ABC%2Fzyz").getDOI()); + assertEquals("10.123:456ABC/zyz", new DOI("http://doi.org/urn:doi:10.123:456ABC%2Fzyz").getDOI()); } @Test public void acceptURLDoi() { // http - Assert.assertEquals("10.1006/jmbi.1998.2354", new DOI("http://doi.org/10.1006/jmbi.1998.2354").getDOI()); + assertEquals("10.1006/jmbi.1998.2354", new DOI("http://doi.org/10.1006/jmbi.1998.2354").getDOI()); // https - Assert.assertEquals("10.1006/jmbi.1998.2354", new DOI("https://doi.org/10.1006/jmbi.1998.2354").getDOI()); + assertEquals("10.1006/jmbi.1998.2354", new DOI("https://doi.org/10.1006/jmbi.1998.2354").getDOI()); // https with % divider - Assert.assertEquals("10.2307/1990888", new DOI("https://dx.doi.org/10.2307%2F1990888").getDOI()); + assertEquals("10.2307/1990888", new DOI("https://dx.doi.org/10.2307%2F1990888").getDOI()); // other domains - Assert.assertEquals("10.1145/1294928.1294933", new DOI("http://doi.acm.org/10.1145/1294928.1294933").getDOI()); - Assert.assertEquals("10.1145/1294928.1294933", new DOI("http://doi.acm.net/10.1145/1294928.1294933").getDOI()); - Assert.assertEquals("10.1145/1294928.1294933", new DOI("http://doi.acm.com/10.1145/1294928.1294933").getDOI()); - Assert.assertEquals("10.1145/1294928.1294933", new DOI("http://doi.acm.de/10.1145/1294928.1294933").getDOI()); - Assert.assertEquals("10.1007/978-3-642-15618-2_19", + assertEquals("10.1145/1294928.1294933", new DOI("http://doi.acm.org/10.1145/1294928.1294933").getDOI()); + assertEquals("10.1145/1294928.1294933", new DOI("http://doi.acm.net/10.1145/1294928.1294933").getDOI()); + assertEquals("10.1145/1294928.1294933", new DOI("http://doi.acm.com/10.1145/1294928.1294933").getDOI()); + assertEquals("10.1145/1294928.1294933", new DOI("http://doi.acm.de/10.1145/1294928.1294933").getDOI()); + assertEquals("10.1007/978-3-642-15618-2_19", new DOI("http://dx.doi.org/10.1007/978-3-642-15618-2_19").getDOI()); - Assert.assertEquals("10.1007/978-3-642-15618-2_19", + assertEquals("10.1007/978-3-642-15618-2_19", new DOI("http://dx.doi.net/10.1007/978-3-642-15618-2_19").getDOI()); - Assert.assertEquals("10.1007/978-3-642-15618-2_19", + assertEquals("10.1007/978-3-642-15618-2_19", new DOI("http://dx.doi.com/10.1007/978-3-642-15618-2_19").getDOI()); - Assert.assertEquals("10.1007/978-3-642-15618-2_19", + assertEquals("10.1007/978-3-642-15618-2_19", new DOI("http://dx.doi.de/10.1007/978-3-642-15618-2_19").getDOI()); - Assert.assertEquals("10.4108/ICST.COLLABORATECOM2009.8275", + assertEquals("10.4108/ICST.COLLABORATECOM2009.8275", new DOI("http://dx.doi.org/10.4108/ICST.COLLABORATECOM2009.8275").getDOI()); - Assert.assertEquals("10.1109/MIC.2012.43", + assertEquals("10.1109/MIC.2012.43", new DOI("http://doi.ieeecomputersociety.org/10.1109/MIC.2012.43").getDOI()); } @@ -89,56 +91,56 @@ public void acceptURLDoi() { public void correctlyDecodeHttpDOIs() { // See http://www.doi.org/doi_handbook/2_Numbering.html#2.5.2.4 // % -> (%25) - Assert.assertEquals("10.1006/rwei.1999%.0001", new DOI("http://doi.org/10.1006/rwei.1999%25.0001").getDOI()); + assertEquals("10.1006/rwei.1999%.0001", new DOI("http://doi.org/10.1006/rwei.1999%25.0001").getDOI()); // " -> (%22) - Assert.assertEquals("10.1006/rwei.1999\".0001", new DOI("http://doi.org/10.1006/rwei.1999%22.0001").getDOI()); + assertEquals("10.1006/rwei.1999\".0001", new DOI("http://doi.org/10.1006/rwei.1999%22.0001").getDOI()); // # -> (%23) - Assert.assertEquals("10.1006/rwei.1999#.0001", new DOI("http://doi.org/10.1006/rwei.1999%23.0001").getDOI()); + assertEquals("10.1006/rwei.1999#.0001", new DOI("http://doi.org/10.1006/rwei.1999%23.0001").getDOI()); // SPACE -> (%20) - Assert.assertEquals("10.1006/rwei.1999 .0001", new DOI("http://doi.org/10.1006/rwei.1999%20.0001").getDOI()); + assertEquals("10.1006/rwei.1999 .0001", new DOI("http://doi.org/10.1006/rwei.1999%20.0001").getDOI()); // ? -> (%3F) - Assert.assertEquals("10.1006/rwei.1999?.0001", new DOI("http://doi.org/10.1006/rwei.1999%3F.0001").getDOI()); + assertEquals("10.1006/rwei.1999?.0001", new DOI("http://doi.org/10.1006/rwei.1999%3F.0001").getDOI()); } @Test public void correctlyEncodeDOIs() { // See http://www.doi.org/doi_handbook/2_Numbering.html#2.5.2.4 // % -> (%25) - Assert.assertEquals("https://doi.org/10.1006/rwei.1999%25.0001", + assertEquals("https://doi.org/10.1006/rwei.1999%25.0001", new DOI("https://doi.org/10.1006/rwei.1999%25.0001").getURIAsASCIIString()); // " -> (%22) - Assert.assertEquals("https://doi.org/10.1006/rwei.1999%22.0001", + assertEquals("https://doi.org/10.1006/rwei.1999%22.0001", new DOI("https://doi.org/10.1006/rwei.1999%22.0001").getURIAsASCIIString()); // # -> (%23) - Assert.assertEquals("https://doi.org/10.1006/rwei.1999%23.0001", + assertEquals("https://doi.org/10.1006/rwei.1999%23.0001", new DOI("https://doi.org/10.1006/rwei.1999%23.0001").getURIAsASCIIString()); // SPACE -> (%20) - Assert.assertEquals("https://doi.org/10.1006/rwei.1999%20.0001", + assertEquals("https://doi.org/10.1006/rwei.1999%20.0001", new DOI("https://doi.org/10.1006/rwei.1999%20.0001").getURIAsASCIIString()); // ? -> (%3F) - Assert.assertEquals("https://doi.org/10.1006/rwei.1999%3F.0001", + assertEquals("https://doi.org/10.1006/rwei.1999%3F.0001", new DOI("https://doi.org/10.1006/rwei.1999%3F.0001").getURIAsASCIIString()); } @Test public void constructCorrectURLForDoi() { // add / to RESOLVER url if missing - Assert.assertEquals("https://doi.org/10.1006/jmbi.1998.2354", + assertEquals("https://doi.org/10.1006/jmbi.1998.2354", new DOI("10.1006/jmbi.1998.2354").getURIAsASCIIString()); - Assert.assertEquals("https://doi.org/10.1006/jmbi.1998.2354", + assertEquals("https://doi.org/10.1006/jmbi.1998.2354", new DOI("https://doi.org/10.1006/jmbi.1998.2354").getURIAsASCIIString()); - Assert.assertEquals("https://doi.org/10.1109/VLHCC.2004.20", + assertEquals("https://doi.org/10.1109/VLHCC.2004.20", new DOI("doi:10.1109/VLHCC.2004.20").getURIAsASCIIString()); } @Test public void findDoiInsideArbitraryText() { - Assert.assertEquals("10.1006/jmbi.1998.2354", + assertEquals("10.1006/jmbi.1998.2354", DOI.findInText("other stuff 10.1006/jmbi.1998.2354 end").get().getDOI()); } @Test public void noDOIFoundInsideArbitraryText() { - Assert.assertEquals(Optional.empty(), DOI.findInText("text without 28282 a doi")); + assertEquals(Optional.empty(), DOI.findInText("text without 28282 a doi")); } } diff --git a/src/test/java/org/jabref/model/entry/identifier/EprintTest.java b/src/test/java/org/jabref/model/entry/identifier/EprintTest.java index 21d1c8c6269..651f05a7566 100644 --- a/src/test/java/org/jabref/model/entry/identifier/EprintTest.java +++ b/src/test/java/org/jabref/model/entry/identifier/EprintTest.java @@ -1,58 +1,58 @@ package org.jabref.model.entry.identifier; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; public class EprintTest { @Test public void acceptPlainEprint() { - Assert.assertEquals("0706.0001", new Eprint("0706.0001").getEprint()); + assertEquals("0706.0001", new Eprint("0706.0001").getEprint()); } @Test public void acceptLegacyEprint() { - Assert.assertEquals("astro-ph.GT/1234567", new Eprint("astro-ph.GT/1234567").getEprint()); - Assert.assertEquals("math/1234567", new Eprint("math/1234567").getEprint()); + assertEquals("astro-ph.GT/1234567", new Eprint("astro-ph.GT/1234567").getEprint()); + assertEquals("math/1234567", new Eprint("math/1234567").getEprint()); } @Test public void acceptPlainEprintWithVersion() { - Assert.assertEquals("0706.0001v1", new Eprint("0706.0001v1").getEprint()); + assertEquals("0706.0001v1", new Eprint("0706.0001v1").getEprint()); } @Test public void ignoreLeadingAndTrailingWhitespaces() { - Assert.assertEquals("0706.0001v1", new Eprint(" 0706.0001v1 ").getEprint()); + assertEquals("0706.0001v1", new Eprint(" 0706.0001v1 ").getEprint()); } - @Test(expected = IllegalArgumentException.class) public void rejectEmbeddedEprint() { - new Eprint("other stuff 0706.0001v1 end"); + assertThrows(IllegalArgumentException.class, () -> new Eprint("other stuff 0706.0001v1 end")); } - @Test(expected = IllegalArgumentException.class) public void rejectInvalidEprint() { - new Eprint("https://thisisnouri"); + assertThrows(IllegalArgumentException.class, () -> new Eprint("https://thisisnouri")); } @Test public void acceptArxivPrefix() { - Assert.assertEquals("0706.0001v1", new Eprint("arXiv:0706.0001v1").getEprint()); + assertEquals("0706.0001v1", new Eprint("arXiv:0706.0001v1").getEprint()); } @Test public void acceptURLEprint() { // http - Assert.assertEquals("0706.0001v1", new Eprint("http://arxiv.org/abs/0706.0001v1").getEprint()); + assertEquals("0706.0001v1", new Eprint("http://arxiv.org/abs/0706.0001v1").getEprint()); // https - Assert.assertEquals("0706.0001v1", new Eprint("https://arxiv.org/abs/0706.0001v1").getEprint()); + assertEquals("0706.0001v1", new Eprint("https://arxiv.org/abs/0706.0001v1").getEprint()); // other domains - Assert.assertEquals("0706.0001v1", new Eprint("https://asdf.org/abs/0706.0001v1").getEprint()); + assertEquals("0706.0001v1", new Eprint("https://asdf.org/abs/0706.0001v1").getEprint()); } @Test public void constructCorrectURLForEprint() { - Assert.assertEquals("http://arxiv.org/abs/0706.0001v1", new Eprint("0706.0001v1").getURIAsASCIIString()); + assertEquals("http://arxiv.org/abs/0706.0001v1", new Eprint("0706.0001v1").getURIAsASCIIString()); } } diff --git a/src/test/java/org/jabref/model/entry/identifier/ISBNTest.java b/src/test/java/org/jabref/model/entry/identifier/ISBNTest.java index 67013c795e5..acd4d4149fe 100644 --- a/src/test/java/org/jabref/model/entry/identifier/ISBNTest.java +++ b/src/test/java/org/jabref/model/entry/identifier/ISBNTest.java @@ -1,9 +1,9 @@ package org.jabref.model.entry.identifier; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; public class ISBNTest { @@ -11,7 +11,6 @@ public class ISBNTest { public void testIsValidFormat10Correct() { assertTrue(new ISBN("0-123456-47-9").isValidFormat()); assertTrue(new ISBN("0-9752298-0-X").isValidFormat()); - } @Test diff --git a/src/test/java/org/jabref/model/entry/identifier/ISSNTest.java b/src/test/java/org/jabref/model/entry/identifier/ISSNTest.java index 7514dd12e3c..d585552e5fe 100644 --- a/src/test/java/org/jabref/model/entry/identifier/ISSNTest.java +++ b/src/test/java/org/jabref/model/entry/identifier/ISSNTest.java @@ -1,10 +1,10 @@ package org.jabref.model.entry.identifier; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; public class ISSNTest { diff --git a/src/test/java/org/jabref/model/entry/identifier/MathSciNetIdTest.java b/src/test/java/org/jabref/model/entry/identifier/MathSciNetIdTest.java index 4d4cd6c63f5..5ec57641415 100644 --- a/src/test/java/org/jabref/model/entry/identifier/MathSciNetIdTest.java +++ b/src/test/java/org/jabref/model/entry/identifier/MathSciNetIdTest.java @@ -2,9 +2,9 @@ import java.util.Optional; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class MathSciNetIdTest { diff --git a/src/test/java/org/jabref/model/entry/specialfields/SpecialFieldTest.java b/src/test/java/org/jabref/model/entry/specialfields/SpecialFieldTest.java index 1a37bfbd86b..23cff29c279 100644 --- a/src/test/java/org/jabref/model/entry/specialfields/SpecialFieldTest.java +++ b/src/test/java/org/jabref/model/entry/specialfields/SpecialFieldTest.java @@ -2,11 +2,11 @@ import java.util.Optional; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; public class SpecialFieldTest { diff --git a/src/test/java/org/jabref/model/groups/AutomaticKeywordGroupTest.java b/src/test/java/org/jabref/model/groups/AutomaticKeywordGroupTest.java index 8fbf4408e25..fc1e792cfef 100644 --- a/src/test/java/org/jabref/model/groups/AutomaticKeywordGroupTest.java +++ b/src/test/java/org/jabref/model/groups/AutomaticKeywordGroupTest.java @@ -5,9 +5,9 @@ import org.jabref.model.entry.BibEntry; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class AutomaticKeywordGroupTest { diff --git a/src/test/java/org/jabref/model/groups/ExplicitGroupTest.java b/src/test/java/org/jabref/model/groups/ExplicitGroupTest.java index 340afa97b34..1b3191fb94d 100644 --- a/src/test/java/org/jabref/model/groups/ExplicitGroupTest.java +++ b/src/test/java/org/jabref/model/groups/ExplicitGroupTest.java @@ -5,12 +5,12 @@ import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.FieldName; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; public class ExplicitGroupTest { @@ -19,7 +19,7 @@ public class ExplicitGroupTest { private BibEntry entry; - @Before + @BeforeEach public void setUp() { group = new ExplicitGroup("myExplicitGroup", GroupHierarchyType.INDEPENDENT, ','); group2 = new ExplicitGroup("myExplicitGroup2", GroupHierarchyType.INCLUDING, ','); @@ -29,7 +29,6 @@ public void setUp() { @Test public void addSingleGroupToEmptyBibEntryChangesGroupsField() { group.add(entry); - assertEquals(Optional.of("myExplicitGroup"), entry.getField(FieldName.GROUPS)); } @@ -37,7 +36,6 @@ public void addSingleGroupToEmptyBibEntryChangesGroupsField() { public void addSingleGroupToNonemptyBibEntryAppendsToGroupsField() { entry.setField(FieldName.GROUPS, "some thing"); group.add(entry); - assertEquals(Optional.of("some thing, myExplicitGroup"), entry.getField(FieldName.GROUPS)); } @@ -45,7 +43,6 @@ public void addSingleGroupToNonemptyBibEntryAppendsToGroupsField() { public void addTwoGroupsToBibEntryChangesGroupsField() { group.add(entry); group2.add(entry); - assertEquals(Optional.of("myExplicitGroup, myExplicitGroup2"), entry.getField(FieldName.GROUPS)); } @@ -53,7 +50,6 @@ public void addTwoGroupsToBibEntryChangesGroupsField() { public void addDuplicateGroupDoesNotChangeGroupsField() throws Exception { entry.setField(FieldName.GROUPS, "myExplicitGroup"); group.add(entry); - assertEquals(Optional.of("myExplicitGroup"), entry.getField(FieldName.GROUPS)); } @@ -62,7 +58,6 @@ public void addDuplicateGroupDoesNotChangeGroupsField() throws Exception { public void removeDoesNotChangeFieldIfContainsNameAsPart() throws Exception { entry.setField(FieldName.GROUPS, "myExplicitGroup_alternative"); group.remove(entry); - assertEquals(Optional.of("myExplicitGroup_alternative"), entry.getField(FieldName.GROUPS)); } @@ -79,7 +74,6 @@ public void removeDoesNotChangeFieldIfContainsNameAsWord() throws Exception { // For https://github.com/JabRef/jabref/issues/1873 public void containsOnlyMatchesCompletePhraseWithWhitespace() throws Exception { entry.setField(FieldName.GROUPS, "myExplicitGroup b"); - assertFalse(group.contains(entry)); } diff --git a/src/test/java/org/jabref/model/groups/GroupTreeNodeTest.java b/src/test/java/org/jabref/model/groups/GroupTreeNodeTest.java index d102c65df05..5126de9da68 100644 --- a/src/test/java/org/jabref/model/groups/GroupTreeNodeTest.java +++ b/src/test/java/org/jabref/model/groups/GroupTreeNodeTest.java @@ -9,12 +9,12 @@ import org.jabref.model.search.matchers.AndMatcher; import org.jabref.model.search.matchers.OrMatcher; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; public class GroupTreeNodeTest { @@ -107,7 +107,7 @@ public static GroupTreeNode getRoot() { return GroupTreeNode.fromGroup(new AllEntriesGroup("All entries")); } - @Before + @BeforeEach public void setUp() throws Exception { entries.clear(); entry = new BibEntry(); diff --git a/src/test/java/org/jabref/model/groups/SearchGroupTest.java b/src/test/java/org/jabref/model/groups/SearchGroupTest.java index 8002b46e9b2..24849ff6e8a 100644 --- a/src/test/java/org/jabref/model/groups/SearchGroupTest.java +++ b/src/test/java/org/jabref/model/groups/SearchGroupTest.java @@ -2,9 +2,9 @@ import org.jabref.model.entry.BibEntry; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertTrue; public class SearchGroupTest { diff --git a/src/test/java/org/jabref/model/groups/TexGroupTest.java b/src/test/java/org/jabref/model/groups/TexGroupTest.java index 7c09efa3915..f9a279ed599 100644 --- a/src/test/java/org/jabref/model/groups/TexGroupTest.java +++ b/src/test/java/org/jabref/model/groups/TexGroupTest.java @@ -9,10 +9,10 @@ import org.jabref.model.entry.BibEntry; import org.jabref.model.util.DummyFileUpdateMonitor; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; public class TexGroupTest { diff --git a/src/test/java/org/jabref/model/groups/WordKeywordGroupTest.java b/src/test/java/org/jabref/model/groups/WordKeywordGroupTest.java index 93e2a9803ec..05f4f83efe0 100644 --- a/src/test/java/org/jabref/model/groups/WordKeywordGroupTest.java +++ b/src/test/java/org/jabref/model/groups/WordKeywordGroupTest.java @@ -5,12 +5,12 @@ import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.FieldName; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; public class WordKeywordGroupTest { @@ -19,7 +19,7 @@ public class WordKeywordGroupTest { private WordKeywordGroup waterGroup; private BibEntry entry; - @Before + @BeforeEach public void setUp() { testGroup = new WordKeywordGroup("name", GroupHierarchyType.INDEPENDENT, "keywords", "test", false, ',', false); testCaseSensitiveGroup = new WordKeywordGroup("name", GroupHierarchyType.INDEPENDENT, "keywords", "test", true, ',', false); diff --git a/src/test/java/org/jabref/model/metadata/MetaDataTest.java b/src/test/java/org/jabref/model/metadata/MetaDataTest.java index 0f43a48cb32..017881ba922 100644 --- a/src/test/java/org/jabref/model/metadata/MetaDataTest.java +++ b/src/test/java/org/jabref/model/metadata/MetaDataTest.java @@ -2,16 +2,16 @@ import java.util.Optional; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class MetaDataTest { private MetaData metaData; - @Before + @BeforeEach public void setUp() { metaData = new MetaData(); } diff --git a/src/test/java/org/jabref/model/pdf/FileAnnotationTest.java b/src/test/java/org/jabref/model/pdf/FileAnnotationTest.java index 376ab2d69de..a96aa095835 100644 --- a/src/test/java/org/jabref/model/pdf/FileAnnotationTest.java +++ b/src/test/java/org/jabref/model/pdf/FileAnnotationTest.java @@ -3,10 +3,10 @@ import java.time.LocalDateTime; import java.time.temporal.ChronoUnit; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static junit.framework.TestCase.assertTrue; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; public class FileAnnotationTest { diff --git a/src/test/java/org/jabref/model/search/matchers/MatcherSetsTest.java b/src/test/java/org/jabref/model/search/matchers/MatcherSetsTest.java index c72d11c1742..acd7e385b6b 100644 --- a/src/test/java/org/jabref/model/search/matchers/MatcherSetsTest.java +++ b/src/test/java/org/jabref/model/search/matchers/MatcherSetsTest.java @@ -3,10 +3,10 @@ import org.jabref.model.entry.BibEntry; import org.jabref.model.search.rules.MockSearchMatcher; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; public class MatcherSetsTest { diff --git a/src/test/java/org/jabref/model/search/rules/ContainBasedSearchRuleTest.java b/src/test/java/org/jabref/model/search/rules/ContainBasedSearchRuleTest.java index c1e6cf6ee64..a31483330f4 100644 --- a/src/test/java/org/jabref/model/search/rules/ContainBasedSearchRuleTest.java +++ b/src/test/java/org/jabref/model/search/rules/ContainBasedSearchRuleTest.java @@ -3,8 +3,9 @@ import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.BibtexEntryTypes; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; /** * Test case for ContainBasedSearchRule. @@ -21,24 +22,24 @@ public void testBasicSearchParsing() { String query = "marine 2001 shields"; - Assert.assertEquals(false, bsCaseSensitive.applyRule(query, be)); - Assert.assertEquals(true, bsCaseInsensitive.applyRule(query, be)); - Assert.assertEquals(false, bsCaseSensitiveRegexp.applyRule(query, be)); - Assert.assertEquals(false, bsCaseInsensitiveRegexp.applyRule(query, be)); + assertEquals(false, bsCaseSensitive.applyRule(query, be)); + assertEquals(true, bsCaseInsensitive.applyRule(query, be)); + assertEquals(false, bsCaseSensitiveRegexp.applyRule(query, be)); + assertEquals(false, bsCaseInsensitiveRegexp.applyRule(query, be)); query = "\"marine larviculture\""; - Assert.assertEquals(false, bsCaseSensitive.applyRule(query, be)); - Assert.assertEquals(false, bsCaseInsensitive.applyRule(query, be)); - Assert.assertEquals(false, bsCaseSensitiveRegexp.applyRule(query, be)); - Assert.assertEquals(false, bsCaseInsensitiveRegexp.applyRule(query, be)); + assertEquals(false, bsCaseSensitive.applyRule(query, be)); + assertEquals(false, bsCaseInsensitive.applyRule(query, be)); + assertEquals(false, bsCaseSensitiveRegexp.applyRule(query, be)); + assertEquals(false, bsCaseInsensitiveRegexp.applyRule(query, be)); query = "marine [A-Za-z]* larviculture"; - Assert.assertEquals(false, bsCaseSensitive.applyRule(query, be)); - Assert.assertEquals(false, bsCaseInsensitive.applyRule(query, be)); - Assert.assertEquals(false, bsCaseSensitiveRegexp.applyRule(query, be)); - Assert.assertEquals(true, bsCaseInsensitiveRegexp.applyRule(query, be)); + assertEquals(false, bsCaseSensitive.applyRule(query, be)); + assertEquals(false, bsCaseInsensitive.applyRule(query, be)); + assertEquals(false, bsCaseSensitiveRegexp.applyRule(query, be)); + assertEquals(true, bsCaseInsensitiveRegexp.applyRule(query, be)); } diff --git a/src/test/java/org/jabref/model/search/rules/SentenceAnalyzerTest.java b/src/test/java/org/jabref/model/search/rules/SentenceAnalyzerTest.java index 6750b1c5229..c75ee11dc4b 100644 --- a/src/test/java/org/jabref/model/search/rules/SentenceAnalyzerTest.java +++ b/src/test/java/org/jabref/model/search/rules/SentenceAnalyzerTest.java @@ -3,9 +3,9 @@ import java.util.Arrays; import java.util.Collections; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class SentenceAnalyzerTest { diff --git a/src/test/java/org/jabref/model/strings/StringUtilTest.java b/src/test/java/org/jabref/model/strings/StringUtilTest.java index 4a870394242..1505d9cb9d2 100644 --- a/src/test/java/org/jabref/model/strings/StringUtilTest.java +++ b/src/test/java/org/jabref/model/strings/StringUtilTest.java @@ -4,10 +4,10 @@ import org.junit.Test; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; public class StringUtilTest { diff --git a/src/test/java/org/jabref/testutils/category/GUITest.java b/src/test/java/org/jabref/testutils/category/GUITest.java index d271ebc129d..c166c80a328 100644 --- a/src/test/java/org/jabref/testutils/category/GUITest.java +++ b/src/test/java/org/jabref/testutils/category/GUITest.java @@ -1,4 +1,17 @@ package org.jabref.testutils.category; -public interface GUITest { +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.junit.jupiter.api.Tag; + +@Target({ElementType.TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +@Tag("GUITest") +public @interface GUITest { + //empty } From 3e134d082c0e40a1043edba1d726036814b60d1d Mon Sep 17 00:00:00 2001 From: Siedlerchr Date: Thu, 8 Feb 2018 00:48:21 +0100 Subject: [PATCH 11/94] fix linked file view model --- .../org/jabref/gui/fieldeditors/LinkedFileViewModel.java | 4 +++- .../jabref/gui/fieldeditors/LinkedFileViewModelTest.java | 7 ++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jabref/gui/fieldeditors/LinkedFileViewModel.java b/src/main/java/org/jabref/gui/fieldeditors/LinkedFileViewModel.java index 3070d518944..31fb9c8cfb8 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/LinkedFileViewModel.java +++ b/src/main/java/org/jabref/gui/fieldeditors/LinkedFileViewModel.java @@ -38,6 +38,7 @@ import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.LinkedFile; +import org.jabref.model.metadata.FileDirectoryPreferences; import de.jensd.fx.glyphs.GlyphIcons; import de.jensd.fx.glyphs.materialdesignicons.MaterialDesignIcon; @@ -281,7 +282,8 @@ public void moveToDefaultDirectory() { } public boolean delete() { - Optional file = linkedFile.findIn(databaseContext, Globals.prefs.getFileDirectoryPreferences()); + FileDirectoryPreferences prefs = Globals.prefs.getFileDirectoryPreferences(); + Optional file = linkedFile.findIn(databaseContext, prefs); if (!file.isPresent()) { LOGGER.warn("Could not find file " + linkedFile.getLink()); diff --git a/src/test/java/org/jabref/gui/fieldeditors/LinkedFileViewModelTest.java b/src/test/java/org/jabref/gui/fieldeditors/LinkedFileViewModelTest.java index b1bfa49ce90..dbb656cf78b 100644 --- a/src/test/java/org/jabref/gui/fieldeditors/LinkedFileViewModelTest.java +++ b/src/test/java/org/jabref/gui/fieldeditors/LinkedFileViewModelTest.java @@ -7,13 +7,14 @@ import javafx.scene.control.Alert.AlertType; import javafx.scene.control.ButtonType; +import org.jabref.Globals; import org.jabref.gui.DialogService; import org.jabref.gui.util.TaskExecutor; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.LinkedFile; import org.jabref.model.metadata.FileDirectoryPreferences; - +import org.jabref.preferences.JabRefPreferences; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -45,6 +46,10 @@ public void setUp() { databaseContext = new BibDatabaseContext(); taskExecutor = mock(TaskExecutor.class); dialogService = mock(DialogService.class); + + Globals.prefs = mock(JabRefPreferences.class); + FileDirectoryPreferences fileDirectoryPreferences = mock(FileDirectoryPreferences.class); + when(Globals.prefs.getFileDirectoryPreferences()).thenReturn(fileDirectoryPreferences); } @Test From e18ad9417c5051cc5fa2898be077c9a6d3f5de64 Mon Sep 17 00:00:00 2001 From: Siedlerchr Date: Thu, 8 Feb 2018 00:51:45 +0100 Subject: [PATCH 12/94] fix build by addingn correct annotation --- .../org/jabref/logic/cleanup/FieldFormatterCleanupTest.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/test/java/org/jabref/logic/cleanup/FieldFormatterCleanupTest.java b/src/test/java/org/jabref/logic/cleanup/FieldFormatterCleanupTest.java index 37833d0c2bc..9f3b76b5bdf 100644 --- a/src/test/java/org/jabref/logic/cleanup/FieldFormatterCleanupTest.java +++ b/src/test/java/org/jabref/logic/cleanup/FieldFormatterCleanupTest.java @@ -1,6 +1,5 @@ package org.jabref.logic.cleanup; - import java.util.HashMap; import java.util.Map; @@ -10,15 +9,15 @@ import org.jabref.model.entry.BibtexEntryTypes; import org.jabref.model.entry.FieldName; -import org.junit.Test; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; public class FieldFormatterCleanupTest { private BibEntry entry; - private Map fieldMap; + private Map fieldMap; @BeforeEach public void setUp() { From 9ab29d596112d3a68fd33b80c5bbe559e5d903f9 Mon Sep 17 00:00:00 2001 From: Siedlerchr Date: Thu, 8 Feb 2018 00:59:17 +0100 Subject: [PATCH 13/94] Pass FileDirectoryPrefs as parameter to delete for testing --- .../gui/fieldeditors/LinkedFileViewModel.java | 3 +- .../LinkedFilesEditorViewModel.java | 8 +++-- .../fieldeditors/LinkedFileViewModelTest.java | 30 +++++++------------ 3 files changed, 17 insertions(+), 24 deletions(-) diff --git a/src/main/java/org/jabref/gui/fieldeditors/LinkedFileViewModel.java b/src/main/java/org/jabref/gui/fieldeditors/LinkedFileViewModel.java index 31fb9c8cfb8..490ccaa05f3 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/LinkedFileViewModel.java +++ b/src/main/java/org/jabref/gui/fieldeditors/LinkedFileViewModel.java @@ -281,8 +281,7 @@ public void moveToDefaultDirectory() { } } - public boolean delete() { - FileDirectoryPreferences prefs = Globals.prefs.getFileDirectoryPreferences(); + public boolean delete(FileDirectoryPreferences prefs) { Optional file = linkedFile.findIn(databaseContext, prefs); if (!file.isPresent()) { diff --git a/src/main/java/org/jabref/gui/fieldeditors/LinkedFilesEditorViewModel.java b/src/main/java/org/jabref/gui/fieldeditors/LinkedFilesEditorViewModel.java index 9891e71e399..6db271022c6 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/LinkedFilesEditorViewModel.java +++ b/src/main/java/org/jabref/gui/fieldeditors/LinkedFilesEditorViewModel.java @@ -89,7 +89,8 @@ private static String getStringRepresentation(List files) { private static LinkedFile fromFile(Path file, List fileDirectories) { String fileExtension = FileHelper.getFileExtension(file).orElse(""); ExternalFileType suggestedFileType = ExternalFileTypes.getInstance() - .getExternalFileTypeByExt(fileExtension).orElse(new UnknownExternalFileType(fileExtension)); + .getExternalFileTypeByExt(fileExtension) + .orElse(new UnknownExternalFileType(fileExtension)); Path relativePath = FileUtil.shortenFileName(file, fileDirectories); return new LinkedFile("", relativePath.toString(), suggestedFileType.getName()); } @@ -111,7 +112,8 @@ public BooleanProperty fulltextLookupInProgressProperty() { } private List parseToFileViewModel(String stringValue) { - return FileFieldParser.parse(stringValue).stream() + return FileFieldParser.parse(stringValue) + .stream() .map(linkedFile -> new LinkedFileViewModel(linkedFile, entry, databaseContext, taskExecutor)) .collect(Collectors.toList()); } @@ -305,7 +307,7 @@ public void deleteFile(LinkedFileViewModel file) { if (file.getFile().isOnlineLink()) { removeFileLink(file); } else { - boolean deleteSuccessful = file.delete(); + boolean deleteSuccessful = file.delete(Globals.prefs.getFileDirectoryPreferences()); if (deleteSuccessful) { files.remove(file); } diff --git a/src/test/java/org/jabref/gui/fieldeditors/LinkedFileViewModelTest.java b/src/test/java/org/jabref/gui/fieldeditors/LinkedFileViewModelTest.java index dbb656cf78b..fd6d832c671 100644 --- a/src/test/java/org/jabref/gui/fieldeditors/LinkedFileViewModelTest.java +++ b/src/test/java/org/jabref/gui/fieldeditors/LinkedFileViewModelTest.java @@ -7,14 +7,13 @@ import javafx.scene.control.Alert.AlertType; import javafx.scene.control.ButtonType; -import org.jabref.Globals; import org.jabref.gui.DialogService; import org.jabref.gui.util.TaskExecutor; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.LinkedFile; import org.jabref.model.metadata.FileDirectoryPreferences; -import org.jabref.preferences.JabRefPreferences; + import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -39,6 +38,7 @@ public class LinkedFileViewModelTest { private BibDatabaseContext databaseContext; private TaskExecutor taskExecutor; private DialogService dialogService; + private final FileDirectoryPreferences fileDirectoryPreferences = mock(FileDirectoryPreferences.class); @Before public void setUp() { @@ -47,9 +47,6 @@ public void setUp() { taskExecutor = mock(TaskExecutor.class); dialogService = mock(DialogService.class); - Globals.prefs = mock(JabRefPreferences.class); - FileDirectoryPreferences fileDirectoryPreferences = mock(FileDirectoryPreferences.class); - when(Globals.prefs.getFileDirectoryPreferences()).thenReturn(fileDirectoryPreferences); } @Test @@ -59,7 +56,7 @@ public void deleteWhenFilePathNotPresentReturnsTrue() { doReturn(Optional.empty()).when(linkedFile).findIn(any(BibDatabaseContext.class), any(FileDirectoryPreferences.class)); LinkedFileViewModel viewModel = new LinkedFileViewModel(linkedFile, entry, databaseContext, taskExecutor, dialogService); - boolean removed = viewModel.delete(); + boolean removed = viewModel.delete(fileDirectoryPreferences); assertTrue(removed); verifyZeroInteractions(dialogService); // dialog was never shown @@ -75,11 +72,10 @@ public void deleteWhenRemoveChosenReturnsTrue() throws IOException { anyString(), any(ButtonType.class), any(ButtonType.class), - any(ButtonType.class) - )).thenAnswer(invocation -> Optional.of(invocation.getArgument(3))); // first vararg - remove button + any(ButtonType.class))).thenAnswer(invocation -> Optional.of(invocation.getArgument(3))); // first vararg - remove button LinkedFileViewModel viewModel = new LinkedFileViewModel(linkedFile, entry, databaseContext, taskExecutor, dialogService); - boolean removed = viewModel.delete(); + boolean removed = viewModel.delete(fileDirectoryPreferences); assertTrue(removed); assertTrue(tempFile.exists()); @@ -95,17 +91,15 @@ public void deleteWhenDeleteChosenReturnsTrueAndDeletesFile() throws IOException anyString(), any(ButtonType.class), any(ButtonType.class), - any(ButtonType.class) - )).thenAnswer(invocation -> Optional.of(invocation.getArgument(4))); // second vararg - delete button + any(ButtonType.class))).thenAnswer(invocation -> Optional.of(invocation.getArgument(4))); // second vararg - delete button LinkedFileViewModel viewModel = new LinkedFileViewModel(linkedFile, entry, databaseContext, taskExecutor, dialogService); - boolean removed = viewModel.delete(); + boolean removed = viewModel.delete(fileDirectoryPreferences); assertTrue(removed); assertFalse(tempFile.exists()); } - @Test public void deleteWhenDeleteChosenAndFileMissingReturnsFalse() throws IOException { linkedFile = new LinkedFile("", "!!nonexistent file!!", ""); @@ -115,11 +109,10 @@ public void deleteWhenDeleteChosenAndFileMissingReturnsFalse() throws IOExceptio anyString(), any(ButtonType.class), any(ButtonType.class), - any(ButtonType.class) - )).thenAnswer(invocation -> Optional.of(invocation.getArgument(4))); // second vararg - delete button + any(ButtonType.class))).thenAnswer(invocation -> Optional.of(invocation.getArgument(4))); // second vararg - delete button LinkedFileViewModel viewModel = new LinkedFileViewModel(linkedFile, entry, databaseContext, taskExecutor, dialogService); - boolean removed = viewModel.delete(); + boolean removed = viewModel.delete(fileDirectoryPreferences); verify(dialogService).showErrorDialogAndWait(anyString(), anyString()); assertFalse(removed); @@ -135,11 +128,10 @@ public void deleteWhenDialogCancelledReturnsFalse() throws IOException { anyString(), any(ButtonType.class), any(ButtonType.class), - any(ButtonType.class) - )).thenAnswer(invocation -> Optional.of(invocation.getArgument(5))); // third vararg - cancel button + any(ButtonType.class))).thenAnswer(invocation -> Optional.of(invocation.getArgument(5))); // third vararg - cancel button LinkedFileViewModel viewModel = new LinkedFileViewModel(linkedFile, entry, databaseContext, taskExecutor, dialogService); - boolean removed = viewModel.delete(); + boolean removed = viewModel.delete(fileDirectoryPreferences); assertFalse(removed); assertTrue(tempFile.exists()); From e1d3ab08ace87e735b7ec5521c77d82dd1c315df Mon Sep 17 00:00:00 2001 From: Siedlerchr Date: Thu, 8 Feb 2018 01:28:02 +0100 Subject: [PATCH 14/94] fix tests --- .../gui/autocompleter/FieldValueSuggestionProviderTest.java | 5 ++--- .../gui/autocompleter/PersonNameSuggestionProviderTest.java | 4 ++-- .../logic/formatter/casechanger/LowerCaseFormatterTest.java | 4 ++-- .../logic/formatter/casechanger/UpperCaseFormatterTest.java | 2 +- src/test/java/org/jabref/logic/layout/LayoutEntryTest.java | 2 +- .../java/org/jabref/logic/openoffice/StyleLoaderTest.java | 6 +++--- .../java/org/jabref/logic/remote/RemotePreferencesTest.java | 2 +- src/test/java/org/jabref/logic/xmp/XMPSchemaBibtexTest.java | 6 ++++-- 8 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/test/java/org/jabref/gui/autocompleter/FieldValueSuggestionProviderTest.java b/src/test/java/org/jabref/gui/autocompleter/FieldValueSuggestionProviderTest.java index ffe219b6200..1366196051a 100644 --- a/src/test/java/org/jabref/gui/autocompleter/FieldValueSuggestionProviderTest.java +++ b/src/test/java/org/jabref/gui/autocompleter/FieldValueSuggestionProviderTest.java @@ -6,8 +6,8 @@ import org.jabref.model.entry.BibEntry; -import org.junit.Test; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import static org.jabref.gui.autocompleter.AutoCompleterUtil.getRequest; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -89,13 +89,12 @@ public void completeLowercaseValueReturnsValue() { assertEquals(Arrays.asList("testValue"), result); } - @Test(expected = NullPointerException.class) public void completeNullThrowsException() { BibEntry entry = new BibEntry(); entry.setField("field", "testKey"); autoCompleter.indexEntry(entry); - autoCompleter.call(getRequest((null))); + assertThrows(NullPointerException.class, () -> autoCompleter.call(getRequest(null))); } @Test diff --git a/src/test/java/org/jabref/gui/autocompleter/PersonNameSuggestionProviderTest.java b/src/test/java/org/jabref/gui/autocompleter/PersonNameSuggestionProviderTest.java index 9974cf50ef5..d3da1439be2 100644 --- a/src/test/java/org/jabref/gui/autocompleter/PersonNameSuggestionProviderTest.java +++ b/src/test/java/org/jabref/gui/autocompleter/PersonNameSuggestionProviderTest.java @@ -7,7 +7,7 @@ import org.jabref.model.entry.Author; import org.jabref.model.entry.BibEntry; -import org.junit.Before; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import static org.jabref.gui.autocompleter.AutoCompleterUtil.getRequest; @@ -24,7 +24,7 @@ public void initAutoCompleterWithNullFieldThrowsException() { assertThrows(NullPointerException.class, () -> new PersonNameSuggestionProvider((String) null)); } - @Before + @BeforeEach public void setUp() throws Exception { autoCompleter = new PersonNameSuggestionProvider("field"); diff --git a/src/test/java/org/jabref/logic/formatter/casechanger/LowerCaseFormatterTest.java b/src/test/java/org/jabref/logic/formatter/casechanger/LowerCaseFormatterTest.java index acfe250974c..abc194048c6 100644 --- a/src/test/java/org/jabref/logic/formatter/casechanger/LowerCaseFormatterTest.java +++ b/src/test/java/org/jabref/logic/formatter/casechanger/LowerCaseFormatterTest.java @@ -1,6 +1,6 @@ package org.jabref.logic.formatter.casechanger; -import org.junit.Before; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -12,7 +12,7 @@ public class LowerCaseFormatterTest { private LowerCaseFormatter formatter; - @Before + @BeforeEach public void setUp() { formatter = new LowerCaseFormatter(); } diff --git a/src/test/java/org/jabref/logic/formatter/casechanger/UpperCaseFormatterTest.java b/src/test/java/org/jabref/logic/formatter/casechanger/UpperCaseFormatterTest.java index 7b406defe37..fd1a2aa2b7a 100644 --- a/src/test/java/org/jabref/logic/formatter/casechanger/UpperCaseFormatterTest.java +++ b/src/test/java/org/jabref/logic/formatter/casechanger/UpperCaseFormatterTest.java @@ -1,7 +1,7 @@ package org.jabref.logic.formatter.casechanger; -import org.junit.Test; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; diff --git a/src/test/java/org/jabref/logic/layout/LayoutEntryTest.java b/src/test/java/org/jabref/logic/layout/LayoutEntryTest.java index 8a471d0d038..0e22039b872 100644 --- a/src/test/java/org/jabref/logic/layout/LayoutEntryTest.java +++ b/src/test/java/org/jabref/logic/layout/LayoutEntryTest.java @@ -5,8 +5,8 @@ import org.jabref.model.entry.BibEntry; -import org.junit.Test; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.mock; diff --git a/src/test/java/org/jabref/logic/openoffice/StyleLoaderTest.java b/src/test/java/org/jabref/logic/openoffice/StyleLoaderTest.java index f6ab59f1c35..4e5d167b07c 100644 --- a/src/test/java/org/jabref/logic/openoffice/StyleLoaderTest.java +++ b/src/test/java/org/jabref/logic/openoffice/StyleLoaderTest.java @@ -10,9 +10,9 @@ import org.jabref.logic.layout.LayoutFormatterPreferences; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; import org.mockito.Answers; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -32,7 +32,7 @@ public class StyleLoaderTest { private Charset encoding; - @Before + @BeforeEach public void setUp() { preferences = mock(OpenOfficePreferences.class, Answers.RETURNS_DEEP_STUBS); layoutPreferences = mock(LayoutFormatterPreferences.class, Answers.RETURNS_DEEP_STUBS); diff --git a/src/test/java/org/jabref/logic/remote/RemotePreferencesTest.java b/src/test/java/org/jabref/logic/remote/RemotePreferencesTest.java index 8094c70046d..3b7b5c85470 100644 --- a/src/test/java/org/jabref/logic/remote/RemotePreferencesTest.java +++ b/src/test/java/org/jabref/logic/remote/RemotePreferencesTest.java @@ -1,7 +1,7 @@ package org.jabref.logic.remote; -import org.junit.Test; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; diff --git a/src/test/java/org/jabref/logic/xmp/XMPSchemaBibtexTest.java b/src/test/java/org/jabref/logic/xmp/XMPSchemaBibtexTest.java index 77e9548805e..c1b4281d0ac 100644 --- a/src/test/java/org/jabref/logic/xmp/XMPSchemaBibtexTest.java +++ b/src/test/java/org/jabref/logic/xmp/XMPSchemaBibtexTest.java @@ -17,7 +17,8 @@ import org.apache.jempbox.impl.XMLUtil; import org.apache.jempbox.xmp.XMPMetadata; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; @@ -32,7 +33,8 @@ public class XMPSchemaBibtexTest { private ImportFormatPreferences prefs; - public void setUp() { + @BeforeEach + public void setup() { prefs = mock(ImportFormatPreferences.class); } From d2e64200f67fa5d747ee1a622180c8f81908db5f Mon Sep 17 00:00:00 2001 From: Siedlerchr Date: Thu, 8 Feb 2018 01:55:49 +0100 Subject: [PATCH 15/94] fix tests --- .../gui/autocompleter/BibEntrySuggestionProviderTest.java | 1 + .../gui/autocompleter/DefaultAutoCompleterTest.java | 1 + .../autocompleter/FieldValueSuggestionProviderTest.java | 2 ++ .../autocompleter/PersonNameSuggestionProviderTest.java | 1 + .../gui/importer/EntryFromFileCreatorManagerTest.java | 5 ++--- .../java/org/jabref/logic/auxparser/AuxParserTest.java | 8 ++++---- .../layout/format/AuthorAndToSemicolonReplacerTest.java | 6 ++++-- .../logic/layout/format/LatexToUnicodeFormatterTest.java | 5 ++--- .../logic/util/strings/StringLengthComparatorTest.java | 4 ++-- .../org/jabref/model/database/BibDatabaseContextTest.java | 4 ++-- src/test/java/org/jabref/model/entry/KeywordListTest.java | 4 ++-- 11 files changed, 23 insertions(+), 18 deletions(-) diff --git a/src/test/java/org/jabref/gui/autocompleter/BibEntrySuggestionProviderTest.java b/src/test/java/org/jabref/gui/autocompleter/BibEntrySuggestionProviderTest.java index 6d7c30023f4..099f6cab1af 100644 --- a/src/test/java/org/jabref/gui/autocompleter/BibEntrySuggestionProviderTest.java +++ b/src/test/java/org/jabref/gui/autocompleter/BibEntrySuggestionProviderTest.java @@ -75,6 +75,7 @@ public void completeLowercaseKeyReturnsKey() { assertEquals(Collections.singletonList(entry), result); } + @Test public void completeNullThrowsException() { BibEntry entry = new BibEntry(); entry.setCiteKey("testKey"); diff --git a/src/test/java/org/jabref/gui/autocompleter/DefaultAutoCompleterTest.java b/src/test/java/org/jabref/gui/autocompleter/DefaultAutoCompleterTest.java index 8a55ecadd10..0a9cba14823 100644 --- a/src/test/java/org/jabref/gui/autocompleter/DefaultAutoCompleterTest.java +++ b/src/test/java/org/jabref/gui/autocompleter/DefaultAutoCompleterTest.java @@ -89,6 +89,7 @@ public void completeLowercaseValueReturnsValue() { assertEquals(Arrays.asList("testValue"), result); } + @Test public void completeNullThrowsException() { BibEntry entry = new BibEntry(); entry.setField("field", "testKey"); diff --git a/src/test/java/org/jabref/gui/autocompleter/FieldValueSuggestionProviderTest.java b/src/test/java/org/jabref/gui/autocompleter/FieldValueSuggestionProviderTest.java index 1366196051a..a8984a6447f 100644 --- a/src/test/java/org/jabref/gui/autocompleter/FieldValueSuggestionProviderTest.java +++ b/src/test/java/org/jabref/gui/autocompleter/FieldValueSuggestionProviderTest.java @@ -22,6 +22,7 @@ public void setUp() throws Exception { autoCompleter = new FieldValueSuggestionProvider("field"); } + @Test public void initAutoCompleterWithNullFieldThrowsException() { assertThrows(NullPointerException.class, () -> new FieldValueSuggestionProvider(null)); } @@ -89,6 +90,7 @@ public void completeLowercaseValueReturnsValue() { assertEquals(Arrays.asList("testValue"), result); } + @Test public void completeNullThrowsException() { BibEntry entry = new BibEntry(); entry.setField("field", "testKey"); diff --git a/src/test/java/org/jabref/gui/autocompleter/PersonNameSuggestionProviderTest.java b/src/test/java/org/jabref/gui/autocompleter/PersonNameSuggestionProviderTest.java index d3da1439be2..dcb9d07e32c 100644 --- a/src/test/java/org/jabref/gui/autocompleter/PersonNameSuggestionProviderTest.java +++ b/src/test/java/org/jabref/gui/autocompleter/PersonNameSuggestionProviderTest.java @@ -89,6 +89,7 @@ public void completeLowercaseBeginningOfNameReturnsName() { assertEquals(Collections.singletonList(vassilisKostakos), result); } + @Test public void completeNullThrowsException() { assertThrows(NullPointerException.class, () -> autoCompleter.call(getRequest((null)))); } diff --git a/src/test/java/org/jabref/gui/importer/EntryFromFileCreatorManagerTest.java b/src/test/java/org/jabref/gui/importer/EntryFromFileCreatorManagerTest.java index 5d3c9aa9411..1d468030d97 100644 --- a/src/test/java/org/jabref/gui/importer/EntryFromFileCreatorManagerTest.java +++ b/src/test/java/org/jabref/gui/importer/EntryFromFileCreatorManagerTest.java @@ -17,7 +17,7 @@ import org.jabref.model.util.DummyFileUpdateMonitor; import org.jabref.testutils.category.GUITest; -import org.junit.Ignore; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -42,7 +42,7 @@ public void testGetCreator() { } @Test - @Ignore + @Disabled public void testAddEntrysFromFiles() throws IOException { try (FileInputStream stream = new FileInputStream(ImportDataTest.UNLINKED_FILES_TEST_BIB); InputStreamReader reader = new InputStreamReader(stream, StandardCharsets.UTF_8)) { @@ -78,5 +78,4 @@ public void testAddEntrysFromFiles() throws IOException { assertFalse(file2Found); } } - } diff --git a/src/test/java/org/jabref/logic/auxparser/AuxParserTest.java b/src/test/java/org/jabref/logic/auxparser/AuxParserTest.java index bc75d7d7f89..4945c9e74c4 100644 --- a/src/test/java/org/jabref/logic/auxparser/AuxParserTest.java +++ b/src/test/java/org/jabref/logic/auxparser/AuxParserTest.java @@ -17,8 +17,8 @@ import org.jabref.model.database.BibDatabase; import org.jabref.model.util.DummyFileUpdateMonitor; -import org.junit.After; -import org.junit.Before; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.Answers; @@ -30,12 +30,12 @@ public class AuxParserTest { private ImportFormatPreferences importFormatPreferences; - @Before + @BeforeEach public void setUp() { importFormatPreferences = mock(ImportFormatPreferences.class, Answers.RETURNS_DEEP_STUBS); } - @After + @AfterEach public void tearDown() { importFormatPreferences = null; } diff --git a/src/test/java/org/jabref/logic/layout/format/AuthorAndToSemicolonReplacerTest.java b/src/test/java/org/jabref/logic/layout/format/AuthorAndToSemicolonReplacerTest.java index 8bbed1ac451..6b77da669cd 100644 --- a/src/test/java/org/jabref/logic/layout/format/AuthorAndToSemicolonReplacerTest.java +++ b/src/test/java/org/jabref/logic/layout/format/AuthorAndToSemicolonReplacerTest.java @@ -4,13 +4,15 @@ import java.util.Collection; import org.jabref.logic.layout.LayoutFormatter; -import static org.junit.jupiter.api.Assertions.*; -import org.junit.jupiter.api.Test; + +import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameter; import org.junit.runners.Parameterized.Parameters; +import static org.junit.Assert.assertEquals; + @RunWith(Parameterized.class) public class AuthorAndToSemicolonReplacerTest { diff --git a/src/test/java/org/jabref/logic/layout/format/LatexToUnicodeFormatterTest.java b/src/test/java/org/jabref/logic/layout/format/LatexToUnicodeFormatterTest.java index 721c855362e..cf4dbb86723 100644 --- a/src/test/java/org/jabref/logic/layout/format/LatexToUnicodeFormatterTest.java +++ b/src/test/java/org/jabref/logic/layout/format/LatexToUnicodeFormatterTest.java @@ -1,11 +1,10 @@ package org.jabref.logic.layout.format; -import org.junit.Ignore; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; - public class LatexToUnicodeFormatterTest { public final LatexToUnicodeFormatter formatter = new LatexToUnicodeFormatter(); @@ -103,7 +102,7 @@ public void testCombiningAccentsCase1() { assertEquals("ḩ", formatter.format("{\\c{h}}")); } - @Ignore("This is not a standard LaTeX command. It is debatable why we should convert this.") + @Disabled("This is not a standard LaTeX command. It is debatable why we should convert this.") @Test public void testCombiningAccentsCase2() { assertEquals("a͍", formatter.format("\\spreadlips{a}")); diff --git a/src/test/java/org/jabref/logic/util/strings/StringLengthComparatorTest.java b/src/test/java/org/jabref/logic/util/strings/StringLengthComparatorTest.java index 3cfb74ea74f..29b691b4e13 100644 --- a/src/test/java/org/jabref/logic/util/strings/StringLengthComparatorTest.java +++ b/src/test/java/org/jabref/logic/util/strings/StringLengthComparatorTest.java @@ -1,6 +1,6 @@ package org.jabref.logic.util.strings; -import org.junit.Before; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -10,7 +10,7 @@ public class StringLengthComparatorTest { private StringLengthComparator slc; - @Before + @BeforeEach public void setUp() { slc = new StringLengthComparator(); } diff --git a/src/test/java/org/jabref/model/database/BibDatabaseContextTest.java b/src/test/java/org/jabref/model/database/BibDatabaseContextTest.java index fed023613b0..8d97da29687 100644 --- a/src/test/java/org/jabref/model/database/BibDatabaseContextTest.java +++ b/src/test/java/org/jabref/model/database/BibDatabaseContextTest.java @@ -7,7 +7,7 @@ import org.jabref.model.metadata.FileDirectoryPreferences; -import org.junit.Before; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -23,7 +23,7 @@ public class BibDatabaseContextTest { // FileDirectoryPreferences) incocation: private FileDirectoryPreferences fileDirPrefs; - @Before + @BeforeEach public void setUp() { fileDirPrefs = mock(FileDirectoryPreferences.class); currentWorkingDir = Paths.get(System.getProperty("user.dir")); diff --git a/src/test/java/org/jabref/model/entry/KeywordListTest.java b/src/test/java/org/jabref/model/entry/KeywordListTest.java index 8edcb36c07d..0b66ca6cc2e 100644 --- a/src/test/java/org/jabref/model/entry/KeywordListTest.java +++ b/src/test/java/org/jabref/model/entry/KeywordListTest.java @@ -2,7 +2,7 @@ import java.util.Optional; -import org.junit.Before; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -11,7 +11,7 @@ public class KeywordListTest { private KeywordList keywords; - @Before + @BeforeEach public void setUp() throws Exception { keywords = new KeywordList(); keywords.add("keywordOne"); From 8d90cb9ef11c872b7e6e11d64f1cb2eded4a8a5c Mon Sep 17 00:00:00 2001 From: Siedlerchr Date: Fri, 9 Feb 2018 13:29:14 +0100 Subject: [PATCH 16/94] fix some more tests remove unnecessary supplier convert some more tests to junit5 fix imports --- src/test/java/org/jabref/CodeStyleTests.java | 2 +- .../java/org/jabref/TestIconsProperties.java | 4 +- .../logic/bibtex/BibEntryWriterTest.java | 25 +- .../logic/bibtex/DuplicateCheckTest.java | 12 +- .../org/jabref/logic/bst/BibtexWidthTest.java | 4 +- .../CitationStyleGeneratorTest.java | 3 +- .../exporter/BibtexDatabaseWriterTest.java | 2 + .../exporter/FieldFormatterCleanupsTest.java | 2 +- .../logic/exporter/GroupSerializerTest.java | 2 +- .../exporter/MetaDataSerializerTest.java | 2 +- .../bibtexfields/RegexFormatterTest.java | 23 +- .../importer/BibDatabaseTestsWithFiles.java | 2 +- .../ImportFormatReaderTestParameterless.java | 1 + .../logic/importer/fetcher/ArXivTest.java | 8 +- .../importer/fetcher/DoiFetcherTest.java | 2 + .../importer/fetcher/FulltextFetcherTest.java | 1 + .../logic/importer/fetcher/GvkParserTest.java | 25 +- .../importer/fetcher/MathSciNetTest.java | 4 +- .../logic/importer/fetcher/zbMATHTest.java | 3 +- .../logic/importer/util/GroupsParserTest.java | 2 + .../org/jabref/logic/l10n/LanguagesTest.java | 1 + .../logic/l10n/LocalizationKeyParamsTest.java | 1 + .../jabref/logic/l10n/LocalizationTest.java | 4 +- .../logic/openoffice/StyleLoaderTest.java | 14 +- .../logic/pdf/PdfAnnotationImporterTest.java | 1 - .../logic/search/DatabaseSearcherTest.java | 8 +- .../jabref/logic/xmp/XMPSchemaBibtexTest.java | 2 +- .../java/org/jabref/model/EntryTypesTest.java | 10 +- .../java/org/jabref/model/TreeNodeTest.java | 48 +- .../model/database/BibDatabaseTest.java | 73 ++- .../database/event/AutosaveEventTest.java | 2 +- .../jabref/model/entry/AuthorListTest.java | 455 +++++++++--------- .../org/jabref/model/entry/BibEntryTest.java | 4 +- .../jabref/model/entry/EntryLinkListTest.java | 2 +- .../org/jabref/model/entry/KeywordTest.java | 2 +- .../jabref/model/strings/StringUtilTest.java | 15 +- 36 files changed, 392 insertions(+), 379 deletions(-) diff --git a/src/test/java/org/jabref/CodeStyleTests.java b/src/test/java/org/jabref/CodeStyleTests.java index 68aead142d6..f2d5f6164d0 100644 --- a/src/test/java/org/jabref/CodeStyleTests.java +++ b/src/test/java/org/jabref/CodeStyleTests.java @@ -18,7 +18,7 @@ public void StringUtilClassIsSmall() throws Exception { Path path = Paths.get("src", "main", "java", StringUtil.class.getName().replace('.', '/') + ".java"); int lineCount = Files.readAllLines(path, StandardCharsets.UTF_8).size(); - assertTrue(lineCount <= 722, () -> "StringUtil increased in size. " + assertTrue(lineCount <= 722, "StringUtil increased in size. " + "We try to keep this class as small as possible. " + "Thus think twice if you add something to StringUtil."); } diff --git a/src/test/java/org/jabref/TestIconsProperties.java b/src/test/java/org/jabref/TestIconsProperties.java index 1b54c3f7dd2..a354ba65470 100644 --- a/src/test/java/org/jabref/TestIconsProperties.java +++ b/src/test/java/org/jabref/TestIconsProperties.java @@ -31,14 +31,14 @@ public void testExistenceOfIconImagesReferencedFromIconsProperties() throws IOEx try (Reader reader = Files.newBufferedReader(Paths.get(iconsPropertiesPath))) { properties.load(reader); } - assertFalse(properties.entrySet().isEmpty(), () -> "There must be loaded properties after loading " + iconsPropertiesPath); + assertFalse(properties.entrySet().isEmpty(), "There must be loaded properties after loading " + iconsPropertiesPath); // check that each key references an existing file for (Map.Entry entry : properties.entrySet()) { String name = entry.getKey().toString(); String value = entry.getValue().toString(); - assertTrue(Files.exists(Paths.get(folder, value)), () -> "Referenced image (" + name + " --> " + value + " does not exist in folder " + folder); + assertTrue(Files.exists(Paths.get(folder, value)), "Referenced image (" + name + " --> " + value + " does not exist in folder " + folder); } // check that each image in the folder is referenced by a key diff --git a/src/test/java/org/jabref/logic/bibtex/BibEntryWriterTest.java b/src/test/java/org/jabref/logic/bibtex/BibEntryWriterTest.java index 4e40233a4ff..7ab162ba874 100644 --- a/src/test/java/org/jabref/logic/bibtex/BibEntryWriterTest.java +++ b/src/test/java/org/jabref/logic/bibtex/BibEntryWriterTest.java @@ -15,21 +15,22 @@ import org.jabref.model.util.DummyFileUpdateMonitor; import org.jabref.model.util.FileUpdateMonitor; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.mockito.Answers; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.mock; public class BibEntryWriterTest { private static ImportFormatPreferences importFormatPreferences; private BibEntryWriter writer; - private FileUpdateMonitor fileMonitor = new DummyFileUpdateMonitor(); + private final FileUpdateMonitor fileMonitor = new DummyFileUpdateMonitor(); - @Before + @BeforeEach public void setUpWriter() { importFormatPreferences = mock(ImportFormatPreferences.class, Answers.RETURNS_DEEP_STUBS); LatexFieldFormatterPreferences latexFieldFormatterPreferences = mock(LatexFieldFormatterPreferences.class, Answers.RETURNS_DEEP_STUBS); @@ -68,11 +69,11 @@ public void testSerialization() throws IOException { public void writeOtherTypeTest() throws Exception { String expected = OS.NEWLINE + "@Other{test," + OS.NEWLINE + " comment = {testentry}," + OS.NEWLINE + - "}"+ OS.NEWLINE; + "}" + OS.NEWLINE; BibEntry entry = new BibEntry(); entry.setType("other"); - entry.setField("Comment","testentry"); + entry.setField("Comment", "testentry"); entry.setCiteKey("test"); //write out bibtex string @@ -87,11 +88,11 @@ public void writeOtherTypeTest() throws Exception { public void writeReallyunknownTypeTest() throws Exception { String expected = OS.NEWLINE + "@Reallyunknowntype{test," + OS.NEWLINE + " comment = {testentry}," + OS.NEWLINE + - "}"+ OS.NEWLINE; + "}" + OS.NEWLINE; BibEntry entry = new BibEntry(); entry.setType("ReallyUnknownType"); - entry.setField("Comment","testentry"); + entry.setField("Comment", "testentry"); entry.setCiteKey("test"); //write out bibtex string @@ -259,7 +260,6 @@ public void testEntryTypeChange() throws IOException { assertEquals(expectedNewEntry, actual); } - @Test public void roundTripWithAppendedNewlines() throws IOException { // @formatter:off @@ -419,14 +419,13 @@ public void trimFieldContents() throws IOException { assertEquals(expected, actual); } - @Test(expected = IOException.class) public void writeThrowsErrorIfFieldContainsUnbalancedBraces() throws IOException { StringWriter stringWriter = new StringWriter(); BibEntry entry = new BibEntry("article"); entry.setField("note", "some text with unbalanced { braces"); - writer.write(entry, stringWriter, BibDatabaseMode.BIBTEX); + assertThrows(IOException.class, () -> writer.write(entry, stringWriter, BibDatabaseMode.BIBTEX)); } @Test diff --git a/src/test/java/org/jabref/logic/bibtex/DuplicateCheckTest.java b/src/test/java/org/jabref/logic/bibtex/DuplicateCheckTest.java index c0a54568f82..ace796173fe 100644 --- a/src/test/java/org/jabref/logic/bibtex/DuplicateCheckTest.java +++ b/src/test/java/org/jabref/logic/bibtex/DuplicateCheckTest.java @@ -5,12 +5,12 @@ import org.jabref.model.entry.BibtexEntryTypes; import org.jabref.model.entry.FieldName; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; public class DuplicateCheckTest { @@ -19,7 +19,7 @@ public class DuplicateCheckTest { private BibEntry simpleInbook; private BibEntry simpleIncollection; - @Before + @BeforeEach public void setUp() { simpleArticle = new BibEntry(BibtexEntryTypes.ARTICLE.getName()) .withField(FieldName.AUTHOR, "Single Author") diff --git a/src/test/java/org/jabref/logic/bst/BibtexWidthTest.java b/src/test/java/org/jabref/logic/bst/BibtexWidthTest.java index 5d64a2a7b74..924165bf5e0 100644 --- a/src/test/java/org/jabref/logic/bst/BibtexWidthTest.java +++ b/src/test/java/org/jabref/logic/bst/BibtexWidthTest.java @@ -1,6 +1,8 @@ package org.jabref.logic.bst; -import org.junit.Test; + + +import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; diff --git a/src/test/java/org/jabref/logic/citationstyle/CitationStyleGeneratorTest.java b/src/test/java/org/jabref/logic/citationstyle/CitationStyleGeneratorTest.java index 3a89099e73d..890eed33bea 100644 --- a/src/test/java/org/jabref/logic/citationstyle/CitationStyleGeneratorTest.java +++ b/src/test/java/org/jabref/logic/citationstyle/CitationStyleGeneratorTest.java @@ -7,7 +7,8 @@ import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; + public class CitationStyleGeneratorTest { diff --git a/src/test/java/org/jabref/logic/exporter/BibtexDatabaseWriterTest.java b/src/test/java/org/jabref/logic/exporter/BibtexDatabaseWriterTest.java index bba2ec0e65a..00a96b5d7fa 100644 --- a/src/test/java/org/jabref/logic/exporter/BibtexDatabaseWriterTest.java +++ b/src/test/java/org/jabref/logic/exporter/BibtexDatabaseWriterTest.java @@ -71,10 +71,12 @@ public void writeWithNullContextThrowsException() throws Exception { assertThrows(NullPointerException.class, () -> databaseWriter.savePartOfDatabase(null, Collections.emptyList(), new SavePreferences())); } + @Test public void writeWithNullEntriesThrowsException() throws Exception { assertThrows(NullPointerException.class, () -> databaseWriter.savePartOfDatabase(bibtexContext, null, new SavePreferences())); } + @Test public void writeWithNullPreferencesThrowsException() throws Exception { assertThrows(NullPointerException.class, () -> databaseWriter.savePartOfDatabase(bibtexContext, Collections.emptyList(), null)); } diff --git a/src/test/java/org/jabref/logic/exporter/FieldFormatterCleanupsTest.java b/src/test/java/org/jabref/logic/exporter/FieldFormatterCleanupsTest.java index 3958a1c5892..ae6a864d198 100644 --- a/src/test/java/org/jabref/logic/exporter/FieldFormatterCleanupsTest.java +++ b/src/test/java/org/jabref/logic/exporter/FieldFormatterCleanupsTest.java @@ -18,7 +18,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class FieldFormatterCleanupsTest { diff --git a/src/test/java/org/jabref/logic/exporter/GroupSerializerTest.java b/src/test/java/org/jabref/logic/exporter/GroupSerializerTest.java index 380515100de..92549163859 100644 --- a/src/test/java/org/jabref/logic/exporter/GroupSerializerTest.java +++ b/src/test/java/org/jabref/logic/exporter/GroupSerializerTest.java @@ -27,7 +27,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class GroupSerializerTest { diff --git a/src/test/java/org/jabref/logic/exporter/MetaDataSerializerTest.java b/src/test/java/org/jabref/logic/exporter/MetaDataSerializerTest.java index 8a9918a0295..df8e04b0bf5 100644 --- a/src/test/java/org/jabref/logic/exporter/MetaDataSerializerTest.java +++ b/src/test/java/org/jabref/logic/exporter/MetaDataSerializerTest.java @@ -17,7 +17,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class MetaDataSerializerTest { diff --git a/src/test/java/org/jabref/logic/formatter/bibtexfields/RegexFormatterTest.java b/src/test/java/org/jabref/logic/formatter/bibtexfields/RegexFormatterTest.java index 4c85a519f90..4ce79fa5d4e 100644 --- a/src/test/java/org/jabref/logic/formatter/bibtexfields/RegexFormatterTest.java +++ b/src/test/java/org/jabref/logic/formatter/bibtexfields/RegexFormatterTest.java @@ -1,8 +1,9 @@ package org.jabref.logic.formatter.bibtexfields; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; /** * Tests in addition to the general tests from {@link org.jabref.logic.formatter.FormatterTest} @@ -11,7 +12,7 @@ public class RegexFormatterTest { private RegexFormatter formatter; - @Before + @BeforeEach public void setUp() { formatter = new RegexFormatter(); } @@ -20,47 +21,47 @@ public void setUp() { public void spacesReplacedCorrectly() { String regexInput = "(\" \",\"-\")"; formatter.setRegex(regexInput); - Assert.assertEquals("replace-all-spaces", formatter.format("replace all spaces")); + assertEquals("replace-all-spaces", formatter.format("replace all spaces")); } @Test public void protectedSpacesNotReplacedInSingleProtectedBlock() { String regexInput = "(\" \",\"-\")"; formatter.setRegex(regexInput); - Assert.assertEquals("replace-spaces-{not these ones}", formatter.format("replace spaces {not these ones}")); + assertEquals("replace-spaces-{not these ones}", formatter.format("replace spaces {not these ones}")); } @Test public void protectedSpacesNotReplacedInTwoProtectedBlocks() { String regexInput = "(\" \",\"-\")"; formatter.setRegex(regexInput); - Assert.assertEquals("replace-spaces-{not these ones}-{or these ones}-but-these-ones", formatter.format("replace spaces {not these ones} {or these ones} but these ones")); + assertEquals("replace-spaces-{not these ones}-{or these ones}-but-these-ones", formatter.format("replace spaces {not these ones} {or these ones} but these ones")); } @Test public void escapedBracesAreNotReplaced() { String regexInput = "(\" \",\"-\")"; formatter.setRegex(regexInput); - Assert.assertEquals("replace-spaces-\\{-these-ones\\}-and-these-ones", formatter.format("replace spaces \\{ these ones\\} and these ones")); + assertEquals("replace-spaces-\\{-these-ones\\}-and-these-ones", formatter.format("replace spaces \\{ these ones\\} and these ones")); } @Test public void escapedBracesAreNotReplacedInTwoCases() { String regexInput = "(\" \",\"-\")"; formatter.setRegex(regexInput); - Assert.assertEquals("replace-spaces-\\{-these-ones\\},-these-ones,-and-\\{-these-ones\\}", formatter.format("replace spaces \\{ these ones\\}, these ones, and \\{ these ones\\}")); + assertEquals("replace-spaces-\\{-these-ones\\},-these-ones,-and-\\{-these-ones\\}", formatter.format("replace spaces \\{ these ones\\}, these ones, and \\{ these ones\\}")); } @Test public void escapedBracesAreNotReplacedAndProtectionStillWorks() { String regexInput = "(\" \",\"-\")"; formatter.setRegex(regexInput); - Assert.assertEquals("replace-spaces-{not these ones},-these-ones,-and-\\{-these-ones\\}", formatter.format("replace spaces {not these ones}, these ones, and \\{ these ones\\}")); + assertEquals("replace-spaces-{not these ones},-these-ones,-and-\\{-these-ones\\}", formatter.format("replace spaces {not these ones}, these ones, and \\{ these ones\\}")); } @Test public void formatExample() { - Assert.assertEquals("Please-replace-the-spaces", formatter.format(formatter.getExampleInput())); + assertEquals("Please-replace-the-spaces", formatter.format(formatter.getExampleInput())); } } diff --git a/src/test/java/org/jabref/logic/importer/BibDatabaseTestsWithFiles.java b/src/test/java/org/jabref/logic/importer/BibDatabaseTestsWithFiles.java index fe4877764cb..f8317b118c6 100644 --- a/src/test/java/org/jabref/logic/importer/BibDatabaseTestsWithFiles.java +++ b/src/test/java/org/jabref/logic/importer/BibDatabaseTestsWithFiles.java @@ -13,7 +13,7 @@ import org.junit.jupiter.api.Test; import org.mockito.Answers; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.mock; public class BibDatabaseTestsWithFiles { diff --git a/src/test/java/org/jabref/logic/importer/ImportFormatReaderTestParameterless.java b/src/test/java/org/jabref/logic/importer/ImportFormatReaderTestParameterless.java index a8336a40f2b..8214133dbcd 100644 --- a/src/test/java/org/jabref/logic/importer/ImportFormatReaderTestParameterless.java +++ b/src/test/java/org/jabref/logic/importer/ImportFormatReaderTestParameterless.java @@ -47,6 +47,7 @@ public void testNullImportUnknownFormatString() throws Exception { } + @Test public void importFromFileWithUnknownFormatThrowsException() throws Exception { assertThrows(NullPointerException.class, () -> reader.importFromFile("someunknownformat", Paths.get("somepath"))); } diff --git a/src/test/java/org/jabref/logic/importer/fetcher/ArXivTest.java b/src/test/java/org/jabref/logic/importer/fetcher/ArXivTest.java index c877430ff9a..166be4e5d39 100644 --- a/src/test/java/org/jabref/logic/importer/fetcher/ArXivTest.java +++ b/src/test/java/org/jabref/logic/importer/fetcher/ArXivTest.java @@ -53,10 +53,9 @@ public void findFullTextForEmptyEntryResultsEmptyOptional() throws IOException { assertEquals(Optional.empty(), finder.findFullText(entry)); } - public void findFullTextRejectsNullParameter() throws IOException { - + @Test + public void findFullTextRejectsNullParameter() { assertThrows(NullPointerException.class, () -> finder.findFullText(null)); - } @Test @@ -71,7 +70,6 @@ public void findFullTextByDOI() throws IOException { @Test public void findFullTextByEprint() throws IOException { entry.setField("eprint", "1603.06570"); - assertEquals(Optional.of(new URL("http://arxiv.org/pdf/1603.06570v1")), finder.findFullText(entry)); } @@ -107,14 +105,12 @@ public void findFullTextByTitleAndPartOfAuthor() throws IOException { @Test public void notFindFullTextByUnknownDOI() throws IOException { entry.setField("doi", "10.1529/unknown"); - assertEquals(Optional.empty(), finder.findFullText(entry)); } @Test public void notFindFullTextByUnknownId() throws IOException { entry.setField("eprint", "1234.12345"); - assertEquals(Optional.empty(), finder.findFullText(entry)); } diff --git a/src/test/java/org/jabref/logic/importer/fetcher/DoiFetcherTest.java b/src/test/java/org/jabref/logic/importer/fetcher/DoiFetcherTest.java index 4c1d006b952..d268730212b 100644 --- a/src/test/java/org/jabref/logic/importer/fetcher/DoiFetcherTest.java +++ b/src/test/java/org/jabref/logic/importer/fetcher/DoiFetcherTest.java @@ -70,10 +70,12 @@ public void testPerformSearchDecker2007() throws FetcherException { assertEquals(Optional.of(bibEntryDecker2007), fetchedEntry); } + @Test public void testPerformSearchEmptyDOI() { assertThrows(FetcherException.class, () -> fetcher.performSearchById("")); } + @Test public void testPerformSearchInvalidDOI() { assertThrows(FetcherException.class, () -> fetcher.performSearchById("10.1002/9781118257517F")); diff --git a/src/test/java/org/jabref/logic/importer/fetcher/FulltextFetcherTest.java b/src/test/java/org/jabref/logic/importer/fetcher/FulltextFetcherTest.java index 6b649d60c7f..20e70601800 100644 --- a/src/test/java/org/jabref/logic/importer/fetcher/FulltextFetcherTest.java +++ b/src/test/java/org/jabref/logic/importer/fetcher/FulltextFetcherTest.java @@ -17,6 +17,7 @@ class FulltextFetcherTest { + @SuppressWarnings("unused") private static List fetcherProvider() { return WebFetchers.getFullTextFetchers(mock(ImportFormatPreferences.class)); } diff --git a/src/test/java/org/jabref/logic/importer/fetcher/GvkParserTest.java b/src/test/java/org/jabref/logic/importer/fetcher/GvkParserTest.java index e7bacbdc8b6..443b46be140 100644 --- a/src/test/java/org/jabref/logic/importer/fetcher/GvkParserTest.java +++ b/src/test/java/org/jabref/logic/importer/fetcher/GvkParserTest.java @@ -10,8 +10,11 @@ import org.jabref.logic.importer.fileformat.GvkParser; import org.jabref.model.entry.BibEntry; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + public class GvkParserTest { @@ -19,8 +22,8 @@ private void doTest(String xmlName, int expectedSize, List resourceNames try (InputStream is = GvkParserTest.class.getResourceAsStream(xmlName)) { GvkParser parser = new GvkParser(); List entries = parser.parseEntries(is); - Assert.assertNotNull(entries); - Assert.assertEquals(expectedSize, entries.size()); + assertNotNull(entries); + assertEquals(expectedSize, entries.size()); int i = 0; for (String resourceName : resourceNames) { BibEntryAssert.assertEquals(GvkParserTest.class, resourceName, entries.get(i)); @@ -49,23 +52,23 @@ public void subTitleTest() throws Exception { try (InputStream is = GvkParserTest.class.getResourceAsStream("gvk_artificial_subtitle_test.xml")) { GvkParser parser = new GvkParser(); List entries = parser.parseEntries(is); - Assert.assertNotNull(entries); - Assert.assertEquals(5, entries.size()); + assertNotNull(entries); + assertEquals(5, entries.size()); BibEntry entry = entries.get(0); - Assert.assertEquals(Optional.empty(), entry.getField("subtitle")); + assertEquals(Optional.empty(), entry.getField("subtitle")); entry = entries.get(1); - Assert.assertEquals(Optional.of("C"), entry.getField("subtitle")); + assertEquals(Optional.of("C"), entry.getField("subtitle")); entry = entries.get(2); - Assert.assertEquals(Optional.of("Word"), entry.getField("subtitle")); + assertEquals(Optional.of("Word"), entry.getField("subtitle")); entry = entries.get(3); - Assert.assertEquals(Optional.of("Word1 word2"), entry.getField("subtitle")); + assertEquals(Optional.of("Word1 word2"), entry.getField("subtitle")); entry = entries.get(4); - Assert.assertEquals(Optional.of("Word1 word2"), entry.getField("subtitle")); + assertEquals(Optional.of("Word1 word2"), entry.getField("subtitle")); } } } diff --git a/src/test/java/org/jabref/logic/importer/fetcher/MathSciNetTest.java b/src/test/java/org/jabref/logic/importer/fetcher/MathSciNetTest.java index 0471675727a..e66d81f0948 100644 --- a/src/test/java/org/jabref/logic/importer/fetcher/MathSciNetTest.java +++ b/src/test/java/org/jabref/logic/importer/fetcher/MathSciNetTest.java @@ -13,8 +13,8 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; diff --git a/src/test/java/org/jabref/logic/importer/fetcher/zbMATHTest.java b/src/test/java/org/jabref/logic/importer/fetcher/zbMATHTest.java index dabb70feb88..41617041ebb 100644 --- a/src/test/java/org/jabref/logic/importer/fetcher/zbMATHTest.java +++ b/src/test/java/org/jabref/logic/importer/fetcher/zbMATHTest.java @@ -13,12 +13,13 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @FetcherTest class zbMATHTest { + private zbMATH fetcher; private BibEntry donaldsonEntry; diff --git a/src/test/java/org/jabref/logic/importer/util/GroupsParserTest.java b/src/test/java/org/jabref/logic/importer/util/GroupsParserTest.java index cccfd5af51f..7d8db0e34cf 100644 --- a/src/test/java/org/jabref/logic/importer/util/GroupsParserTest.java +++ b/src/test/java/org/jabref/logic/importer/util/GroupsParserTest.java @@ -57,6 +57,7 @@ public void HierarchicalDelimiterThatNeedsToBeEscaped() throws Exception { assertEquals(expected, parsed); } + @Test public void fromStringThrowsParseExceptionForNotEscapedGroupName() throws Exception { assertThrows(ParseException.class, () -> GroupsParser.fromString("ExplicitGroup:slit\\\\;0\\;mertsch_slit2_2007\\;;", ',', fileMonitor)); } @@ -122,6 +123,7 @@ public void fromStringParsesTexGroup() throws Exception { assertEquals(expected, parsed); } + @Test public void fromStringUnknownGroupThrowsException() throws Exception { assertThrows(ParseException.class, () -> GroupsParser.fromString("0 UnknownGroup:myUnknownGroup;0;;1;;;;", ',', fileMonitor)); } diff --git a/src/test/java/org/jabref/logic/l10n/LanguagesTest.java b/src/test/java/org/jabref/logic/l10n/LanguagesTest.java index 9df1198cbfa..25f9612b772 100644 --- a/src/test/java/org/jabref/logic/l10n/LanguagesTest.java +++ b/src/test/java/org/jabref/logic/l10n/LanguagesTest.java @@ -48,6 +48,7 @@ public void convertUnknownKnownLanguageAndUnknownCountry() { assertEquals(Optional.empty(), Languages.convertToSupportedLocale("language_country_variant")); } + @Test public void convertToKnownLocaleNull() { assertThrows(NullPointerException.class, () -> Languages.convertToSupportedLocale(null)); } diff --git a/src/test/java/org/jabref/logic/l10n/LocalizationKeyParamsTest.java b/src/test/java/org/jabref/logic/l10n/LocalizationKeyParamsTest.java index e64146731e3..0edc4975f8b 100644 --- a/src/test/java/org/jabref/logic/l10n/LocalizationKeyParamsTest.java +++ b/src/test/java/org/jabref/logic/l10n/LocalizationKeyParamsTest.java @@ -16,6 +16,7 @@ public void testReplacePlaceholders() { assertEquals("What \n : %e %c_a b", new LocalizationKeyParams("What \n : %e %c_%0 %1", "a", "b").replacePlaceholders()); } + @Test public void testTooManyParams() { assertThrows(IllegalStateException.class, () -> new LocalizationKeyParams("", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0")); } diff --git a/src/test/java/org/jabref/logic/l10n/LocalizationTest.java b/src/test/java/org/jabref/logic/l10n/LocalizationTest.java index e139735abd6..e7b91573816 100644 --- a/src/test/java/org/jabref/logic/l10n/LocalizationTest.java +++ b/src/test/java/org/jabref/logic/l10n/LocalizationTest.java @@ -6,7 +6,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class LocalizationTest { @@ -67,7 +67,7 @@ public void testKnownGermanTranslation() { Localization.setLanguage("de"); String knownKey = "Save all"; assertEquals("Alle speichern", Localization.lang(knownKey)); - assertEquals( "A&lle speichern", Localization.menuTitle(knownKey)); + assertEquals("A&lle speichern", Localization.menuTitle(knownKey)); } @Test diff --git a/src/test/java/org/jabref/logic/openoffice/StyleLoaderTest.java b/src/test/java/org/jabref/logic/openoffice/StyleLoaderTest.java index 4e5d167b07c..945b70fa356 100644 --- a/src/test/java/org/jabref/logic/openoffice/StyleLoaderTest.java +++ b/src/test/java/org/jabref/logic/openoffice/StyleLoaderTest.java @@ -11,7 +11,6 @@ import org.jabref.logic.layout.LayoutFormatterPreferences; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.mockito.Answers; @@ -40,15 +39,18 @@ public void setUp() { } + @Test public void throwNPEWithNullPreferences() { assertThrows(NullPointerException.class, () -> loader = new StyleLoader(null, layoutPreferences, mock(Charset.class))); } + @Test public void throwNPEWithNullLayoutPreferences() { assertThrows(NullPointerException.class, () -> loader = new StyleLoader(mock(OpenOfficePreferences.class), null, mock(Charset.class))); } + @Test public void throwNPEWithNullCharset() { assertThrows(NullPointerException.class, () -> loader = new StyleLoader(mock(OpenOfficePreferences.class), layoutPreferences, null)); } @@ -120,7 +122,6 @@ public void testInitalizeWithOneExternalFileRemoveStyle() throws URISyntaxExcept } @Test - @Disabled("This tests the preferences that are mocked away") public void testInitalizeWithOneExternalFileRemoveStyleUpdatesPreferences() throws URISyntaxException { String filename = Paths.get(StyleLoader.class.getResource(StyleLoader.DEFAULT_AUTHORYEAR_STYLE_PATH).toURI()) .toFile().getPath(); @@ -137,7 +138,8 @@ public void testInitalizeWithOneExternalFileRemoveStyleUpdatesPreferences() thro for (OOBibStyle style : toremove) { assertTrue(loader.removeStyle(style)); } - assertTrue(preferences.getExternalStyles().isEmpty()); + //As the prefs are mocked away, the getExternalStyles still returns the initial one + assertFalse(preferences.getExternalStyles().isEmpty()); } @Test @@ -152,7 +154,7 @@ public void testAddSameStyleTwiceLeadsToOneMoreStyle() throws URISyntaxException assertEquals(beforeAdding + 1, loader.getStyles().size()); } - + @Test public void testAddNullStyleThrowsNPE() { loader = new StyleLoader(preferences, layoutPreferences, encoding); assertThrows(NullPointerException.class, () -> loader.addStyleIfValid(null)); @@ -181,14 +183,12 @@ public void testGetStoredUsedStyle() { } @Test - @Disabled("This tests the preferences that are mocked away") - public void testGtDefaultUsedStyleWhenIncorrect() { + public void testGetDefaultUsedStyleWhenIncorrect() { when(preferences.getCurrentStyle()).thenReturn("ljlkjlkjnljnvdlsjniuhwelfhuewfhlkuewhfuwhelu"); loader = new StyleLoader(preferences, layoutPreferences, encoding); OOBibStyle style = loader.getUsedStyle(); assertTrue(style.isValid()); assertEquals(StyleLoader.DEFAULT_AUTHORYEAR_STYLE_PATH, style.getPath()); - assertEquals(StyleLoader.DEFAULT_AUTHORYEAR_STYLE_PATH, preferences.getCurrentStyle()); } @Test diff --git a/src/test/java/org/jabref/logic/pdf/PdfAnnotationImporterTest.java b/src/test/java/org/jabref/logic/pdf/PdfAnnotationImporterTest.java index 705f2f291bd..01bb95f00ea 100644 --- a/src/test/java/org/jabref/logic/pdf/PdfAnnotationImporterTest.java +++ b/src/test/java/org/jabref/logic/pdf/PdfAnnotationImporterTest.java @@ -103,7 +103,6 @@ public void squigglyWithNoteMinimal() { } @Test - public void strikeoutWithNoteMinimal() { final FileAnnotation expectedLinkedAnnotation = new FileAnnotation("lynyus", LocalDateTime.of(2017, 6, 1, 13, 2, 3), 1, "striked out", FileAnnotationType.STRIKEOUT, Optional.empty()); diff --git a/src/test/java/org/jabref/logic/search/DatabaseSearcherTest.java b/src/test/java/org/jabref/logic/search/DatabaseSearcherTest.java index e9ac4ba2cd6..b5c18e1234d 100644 --- a/src/test/java/org/jabref/logic/search/DatabaseSearcherTest.java +++ b/src/test/java/org/jabref/logic/search/DatabaseSearcherTest.java @@ -7,10 +7,10 @@ import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.BibtexEntryTypes; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class DatabaseSearcherTest { @@ -19,7 +19,7 @@ public class DatabaseSearcherTest { private BibDatabase database; - @Before + @BeforeEach public void setUp() { database = new BibDatabase(); } diff --git a/src/test/java/org/jabref/logic/xmp/XMPSchemaBibtexTest.java b/src/test/java/org/jabref/logic/xmp/XMPSchemaBibtexTest.java index c1b4281d0ac..377ffebaa9e 100644 --- a/src/test/java/org/jabref/logic/xmp/XMPSchemaBibtexTest.java +++ b/src/test/java/org/jabref/logic/xmp/XMPSchemaBibtexTest.java @@ -34,7 +34,7 @@ public class XMPSchemaBibtexTest { private ImportFormatPreferences prefs; @BeforeEach - public void setup() { + public void setUp() { prefs = mock(ImportFormatPreferences.class); } diff --git a/src/test/java/org/jabref/model/EntryTypesTest.java b/src/test/java/org/jabref/model/EntryTypesTest.java index bd928059154..019ca85d04d 100644 --- a/src/test/java/org/jabref/model/EntryTypesTest.java +++ b/src/test/java/org/jabref/model/EntryTypesTest.java @@ -26,10 +26,10 @@ @RunWith(Parameterized.class) public class EntryTypesTest { - private BibDatabaseMode mode; - private BibDatabaseMode otherMode; - private EntryType standardArticleType; - private EntryType defaultType; + private final BibDatabaseMode mode; + private final BibDatabaseMode otherMode; + private final EntryType standardArticleType; + private final EntryType defaultType; private CustomEntryType newCustomType; private CustomEntryType overwrittenStandardType; @@ -43,7 +43,7 @@ public EntryTypesTest(BibDatabaseMode mode) { @Parameterized.Parameters public static Object[] data() { - return new Object[] { BibDatabaseMode.BIBTEX, BibDatabaseMode.BIBLATEX }; + return new Object[] {BibDatabaseMode.BIBTEX, BibDatabaseMode.BIBLATEX}; } @Before diff --git a/src/test/java/org/jabref/model/TreeNodeTest.java b/src/test/java/org/jabref/model/TreeNodeTest.java index 10aed3d70c9..1c4d2b989b9 100644 --- a/src/test/java/org/jabref/model/TreeNodeTest.java +++ b/src/test/java/org/jabref/model/TreeNodeTest.java @@ -6,26 +6,29 @@ import java.util.Optional; import java.util.function.Consumer; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; -@RunWith(MockitoJUnitRunner.class) public class TreeNodeTest { - @Mock Consumer subscriber; - @Test(expected = UnsupportedOperationException.class) + @BeforeEach + public void setUp() { + subscriber = mock(Consumer.class); + } + public void constructorChecksThatClassImplementsCorrectInterface() { - new WrongTreeNodeImplementation(); + assertThrows(UnsupportedOperationException.class, () -> new WrongTreeNodeImplementation()); + } @Test @@ -79,10 +82,10 @@ public void getDescendantNonExistentReturnsEmpty() { assertEquals(Optional.empty(), root.getDescendant(Arrays.asList(1, 100, 0))); } - @Test(expected = UnsupportedOperationException.class) + @Test public void getPositionInParentForRootThrowsException() { TreeNodeTestData.TreeNodeMock root = new TreeNodeTestData.TreeNodeMock(); - root.getPositionInParent(); + assertThrows(UnsupportedOperationException.class, () -> root.getPositionInParent()); } @Test @@ -102,7 +105,7 @@ public void getIndexOfNonExistentChildReturnsEmpty() { public void getIndexOfChild() { TreeNodeTestData.TreeNodeMock root = new TreeNodeTestData.TreeNodeMock(); TreeNodeTestData.TreeNodeMock node = TreeNodeTestData.getNodeAsChild(root); - assertEquals((Integer)2, root.getIndexOfChild(node).get()); + assertEquals((Integer) 2, root.getIndexOfChild(node).get()); } @Test @@ -140,7 +143,7 @@ public void moveToAddsAsLastChildInSimpleTree() { TreeNodeTestData.TreeNodeMock root = new TreeNodeTestData.TreeNodeMock(); TreeNodeTestData.TreeNodeMock node = TreeNodeTestData.getNodeInSimpleTree(root); node.moveTo(root); - assertEquals((Integer)2, root.getIndexOfChild(node).get()); + assertEquals((Integer) 2, root.getIndexOfChild(node).get()); } @Test @@ -148,7 +151,7 @@ public void moveToAddsAsLastChildInComplexTree() { TreeNodeTestData.TreeNodeMock root = new TreeNodeTestData.TreeNodeMock(); TreeNodeTestData.TreeNodeMock node = TreeNodeTestData.getNodeInComplexTree(root); node.moveTo(root); - assertEquals((Integer)4, root.getIndexOfChild(node).get()); + assertEquals((Integer) 4, root.getIndexOfChild(node).get()); } @Test @@ -478,11 +481,11 @@ public void removeChildIndexRemovesNodeFromChildrenCollection() { assertFalse(root.getChildren().contains(node)); } - @Test(expected = UnsupportedOperationException.class) + @Test public void addThrowsExceptionIfNodeHasParent() { TreeNodeTestData.TreeNodeMock root = new TreeNodeTestData.TreeNodeMock(); TreeNodeTestData.TreeNodeMock node = TreeNodeTestData.getNodeAsChild(root); - root.addChild(node); + assertThrows(UnsupportedOperationException.class, () -> root.addChild(node)); } @Test @@ -514,12 +517,12 @@ public void moveAllChildrenToChangesParent() { assertEquals(root, child2.getParent().get()); } - @Test(expected = UnsupportedOperationException.class) + @Test public void moveAllChildrenToDescendantThrowsException() { TreeNodeTestData.TreeNodeMock root = new TreeNodeTestData.TreeNodeMock(); TreeNodeTestData.TreeNodeMock node = TreeNodeTestData.getNodeAsChild(root); - root.moveAllChildrenTo(node, 0); + assertThrows(UnsupportedOperationException.class, () -> root.moveAllChildrenTo(node, 0)); } @Test @@ -621,6 +624,7 @@ public void findChildrenWithSameName() throws Exception { } private static class WrongTreeNodeImplementation extends TreeNode { + // This class is a wrong derived class of TreeNode // since it does not extends TreeNode // See test constructorChecksThatClassImplementsCorrectInterface diff --git a/src/test/java/org/jabref/model/database/BibDatabaseTest.java b/src/test/java/org/jabref/model/database/BibDatabaseTest.java index a6b97c24ccb..4a11fdc737d 100644 --- a/src/test/java/org/jabref/model/database/BibDatabaseTest.java +++ b/src/test/java/org/jabref/model/database/BibDatabaseTest.java @@ -15,31 +15,24 @@ import org.jabref.model.entry.IdGenerator; import org.jabref.model.event.TestEventListener; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; public class BibDatabaseTest { - @Rule - public ExpectedException thrown = ExpectedException.none(); - private BibDatabase database; - @Before + @BeforeEach public void setUp() { database = new BibDatabase(); } - @Test public void insertEntryAddsEntryToEntriesList() { BibEntry entry = new BibEntry(); @@ -57,15 +50,15 @@ public void containsEntryIdFindsEntry() { assertTrue(database.containsEntryWithId(entry.getId())); } - @Test(expected = KeyCollisionException.class) + @Test public void insertEntryWithSameIdThrowsException() { BibEntry entry0 = new BibEntry(); database.insertEntry(entry0); BibEntry entry1 = new BibEntry(); entry1.setId(entry0.getId()); - database.insertEntry(entry1); - fail(); + assertThrows(KeyCollisionException.class, () -> database.insertEntry(entry1)); + } @Test @@ -78,16 +71,14 @@ public void removeEntryRemovesEntryFromEntriesList() { assertFalse(database.containsEntryWithId(entry.getId())); } - @Test(expected = NullPointerException.class) + @Test public void insertNullEntryThrowsException() { - database.insertEntry(null); - fail(); + assertThrows(NullPointerException.class, () -> database.insertEntry(null)); } - @Test(expected = NullPointerException.class) + @Test public void removeNullEntryThrowsException() { - database.removeEntry(null); - fail(); + assertThrows(NullPointerException.class, () -> database.removeEntry(null)); } @Test @@ -123,30 +114,32 @@ public void removeStringUpdatesStringList() { @Test public void hasStringLabelFindsString() { - BibtexString string = new BibtexString( "DSP", "Digital Signal Processing"); + BibtexString string = new BibtexString("DSP", "Digital Signal Processing"); database.addString(string); assertTrue(database.hasStringLabel("DSP")); assertFalse(database.hasStringLabel("VLSI")); } - @Test(expected = KeyCollisionException.class) + @Test public void addSameStringLabelTwiceThrowsKeyCollisionException() { BibtexString string = new BibtexString("DSP", "Digital Signal Processing"); database.addString(string); - string = new BibtexString("DSP", "Digital Signal Processor"); - database.addString(string); - fail(); + final BibtexString finalString = new BibtexString("DSP", "Digital Signal Processor"); + + assertThrows(KeyCollisionException.class, () -> database.addString(finalString)); + } - @Test(expected = KeyCollisionException.class) + @Test public void addSameStringIdTwiceThrowsKeyCollisionException() { - BibtexString string = new BibtexString( "DSP", "Digital Signal Processing"); - string.setId("duplicateid"); - database.addString(string); - string = new BibtexString("VLSI", "Very Large Scale Integration"); + BibtexString string = new BibtexString("DSP", "Digital Signal Processing"); string.setId("duplicateid"); database.addString(string); - fail(); + final BibtexString finalString = new BibtexString("VLSI", "Very Large Scale Integration"); + finalString.setId("duplicateid"); + + assertThrows(KeyCollisionException.class, () -> database.addString(finalString)); + } @Test @@ -227,11 +220,11 @@ public void circularStringResolving() { public void circularStringResolvingLongerCycle() { BibtexString string = new BibtexString("AAA", "#BBB#"); database.addString(string); - string = new BibtexString( "BBB", "#CCC#"); + string = new BibtexString("BBB", "#CCC#"); database.addString(string); string = new BibtexString("CCC", "#DDD#"); database.addString(string); - string = new BibtexString( "DDD", "#AAA#"); + string = new BibtexString("DDD", "#AAA#"); database.addString(string); assertEquals("AAA", database.resolveForStrings("#AAA#")); assertEquals("BBB", database.resolveForStrings("#BBB#")); @@ -262,9 +255,9 @@ public void resolveForStringsOddHashMarkAtTheEnd() { public void getUsedStrings() { BibEntry entry = new BibEntry(IdGenerator.next()); entry.setField("author", "#AAA#"); - BibtexString tripleA = new BibtexString( "AAA", "Some other #BBB#"); - BibtexString tripleB = new BibtexString( "BBB", "Some more text"); - BibtexString tripleC = new BibtexString( "CCC", "Even more text"); + BibtexString tripleA = new BibtexString("AAA", "Some other #BBB#"); + BibtexString tripleB = new BibtexString("BBB", "Some more text"); + BibtexString tripleC = new BibtexString("CCC", "Even more text"); Set stringSet = new HashSet<>(); stringSet.add(tripleA); stringSet.add(tripleB); diff --git a/src/test/java/org/jabref/model/database/event/AutosaveEventTest.java b/src/test/java/org/jabref/model/database/event/AutosaveEventTest.java index 280a2b70c96..10ed6f709de 100644 --- a/src/test/java/org/jabref/model/database/event/AutosaveEventTest.java +++ b/src/test/java/org/jabref/model/database/event/AutosaveEventTest.java @@ -2,7 +2,7 @@ import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNotNull; public class AutosaveEventTest { diff --git a/src/test/java/org/jabref/model/entry/AuthorListTest.java b/src/test/java/org/jabref/model/entry/AuthorListTest.java index 3926e212f54..73a15650267 100644 --- a/src/test/java/org/jabref/model/entry/AuthorListTest.java +++ b/src/test/java/org/jabref/model/entry/AuthorListTest.java @@ -2,8 +2,12 @@ import java.util.Optional; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; public class AuthorListTest { @@ -13,15 +17,15 @@ public static int size(String bibtex) { @Test public void testFixAuthorNatbib() { - Assert.assertEquals("", AuthorList.fixAuthorNatbib("")); - Assert.assertEquals("Smith", AuthorList.fixAuthorNatbib("John Smith")); - Assert.assertEquals("Smith and Black Brown", AuthorList + assertEquals("", AuthorList.fixAuthorNatbib("")); + assertEquals("Smith", AuthorList.fixAuthorNatbib("John Smith")); + assertEquals("Smith and Black Brown", AuthorList .fixAuthorNatbib("John Smith and Black Brown, Peter")); - Assert.assertEquals("von Neumann et al.", AuthorList + assertEquals("von Neumann et al.", AuthorList .fixAuthorNatbib("John von Neumann and John Smith and Black Brown, Peter")); // Is not cached! - Assert.assertTrue(AuthorList + assertTrue(AuthorList .fixAuthorNatbib("John von Neumann and John Smith and Black Brown, Peter").equals(AuthorList .fixAuthorNatbib("John von Neumann and John Smith and Black Brown, Peter"))); @@ -31,93 +35,93 @@ public void testFixAuthorNatbib() { public void testGetAuthorList() { // Test caching in authorCache. AuthorList al = AuthorList.parse("John Smith"); - Assert.assertEquals(al, AuthorList.parse("John Smith")); - Assert.assertFalse(al.equals(AuthorList.parse("Smith"))); + assertEquals(al, AuthorList.parse("John Smith")); + assertFalse(al.equals(AuthorList.parse("Smith"))); } @Test public void testFixAuthorFirstNameFirstCommas() { // No Commas - Assert.assertEquals("", AuthorList.fixAuthorFirstNameFirstCommas("", true, false)); - Assert.assertEquals("", AuthorList.fixAuthorFirstNameFirstCommas("", false, false)); + assertEquals("", AuthorList.fixAuthorFirstNameFirstCommas("", true, false)); + assertEquals("", AuthorList.fixAuthorFirstNameFirstCommas("", false, false)); - Assert.assertEquals("John Smith", AuthorList.fixAuthorFirstNameFirstCommas("John Smith", + assertEquals("John Smith", AuthorList.fixAuthorFirstNameFirstCommas("John Smith", false, false)); - Assert.assertEquals("J. Smith", AuthorList.fixAuthorFirstNameFirstCommas("John Smith", true, + assertEquals("J. Smith", AuthorList.fixAuthorFirstNameFirstCommas("John Smith", true, false)); // Check caching - Assert.assertTrue(AuthorList.fixAuthorFirstNameFirstCommas( + assertTrue(AuthorList.fixAuthorFirstNameFirstCommas( "John von Neumann and John Smith and Black Brown, Peter", true, false).equals( AuthorList .fixAuthorFirstNameFirstCommas("John von Neumann and John Smith and Black Brown, Peter", true, false))); - Assert.assertEquals("John Smith and Peter Black Brown", AuthorList + assertEquals("John Smith and Peter Black Brown", AuthorList .fixAuthorFirstNameFirstCommas("John Smith and Black Brown, Peter", false, false)); - Assert.assertEquals("J. Smith and P. Black Brown", AuthorList.fixAuthorFirstNameFirstCommas( + assertEquals("J. Smith and P. Black Brown", AuthorList.fixAuthorFirstNameFirstCommas( "John Smith and Black Brown, Peter", true, false)); // Method description is different than code -> additional comma // there - Assert.assertEquals("John von Neumann, John Smith and Peter Black Brown", AuthorList + assertEquals("John von Neumann, John Smith and Peter Black Brown", AuthorList .fixAuthorFirstNameFirstCommas( "John von Neumann and John Smith and Black Brown, Peter", false, false)); - Assert.assertEquals("J. von Neumann, J. Smith and P. Black Brown", AuthorList + assertEquals("J. von Neumann, J. Smith and P. Black Brown", AuthorList .fixAuthorFirstNameFirstCommas( "John von Neumann and John Smith and Black Brown, Peter", true, false)); - Assert.assertEquals("J. P. von Neumann", AuthorList.fixAuthorFirstNameFirstCommas( + assertEquals("J. P. von Neumann", AuthorList.fixAuthorFirstNameFirstCommas( "John Peter von Neumann", true, false)); // Oxford Commas - Assert.assertEquals("", AuthorList.fixAuthorFirstNameFirstCommas("", true, true)); - Assert.assertEquals("", AuthorList.fixAuthorFirstNameFirstCommas("", false, true)); + assertEquals("", AuthorList.fixAuthorFirstNameFirstCommas("", true, true)); + assertEquals("", AuthorList.fixAuthorFirstNameFirstCommas("", false, true)); - Assert.assertEquals("John Smith", AuthorList.fixAuthorFirstNameFirstCommas("John Smith", + assertEquals("John Smith", AuthorList.fixAuthorFirstNameFirstCommas("John Smith", false, true)); - Assert.assertEquals("J. Smith", AuthorList.fixAuthorFirstNameFirstCommas("John Smith", true, + assertEquals("J. Smith", AuthorList.fixAuthorFirstNameFirstCommas("John Smith", true, true)); // Check caching - Assert.assertTrue(AuthorList.fixAuthorFirstNameFirstCommas( + assertTrue(AuthorList.fixAuthorFirstNameFirstCommas( "John von Neumann and John Smith and Black Brown, Peter", true, true).equals( AuthorList .fixAuthorFirstNameFirstCommas("John von Neumann and John Smith and Black Brown, Peter", true, true))); - Assert.assertEquals("John Smith and Peter Black Brown", AuthorList + assertEquals("John Smith and Peter Black Brown", AuthorList .fixAuthorFirstNameFirstCommas("John Smith and Black Brown, Peter", false, true)); - Assert.assertEquals("J. Smith and P. Black Brown", AuthorList.fixAuthorFirstNameFirstCommas( + assertEquals("J. Smith and P. Black Brown", AuthorList.fixAuthorFirstNameFirstCommas( "John Smith and Black Brown, Peter", true, true)); // Method description is different than code -> additional comma // there - Assert.assertEquals("John von Neumann, John Smith, and Peter Black Brown", AuthorList + assertEquals("John von Neumann, John Smith, and Peter Black Brown", AuthorList .fixAuthorFirstNameFirstCommas( "John von Neumann and John Smith and Black Brown, Peter", false, true)); - Assert.assertEquals("J. von Neumann, J. Smith, and P. Black Brown", AuthorList + assertEquals("J. von Neumann, J. Smith, and P. Black Brown", AuthorList .fixAuthorFirstNameFirstCommas( "John von Neumann and John Smith and Black Brown, Peter", true, true)); - Assert.assertEquals("J. P. von Neumann", AuthorList.fixAuthorFirstNameFirstCommas( + assertEquals("J. P. von Neumann", AuthorList.fixAuthorFirstNameFirstCommas( "John Peter von Neumann", true, true)); } @Test public void testFixAuthorFirstNameFirst() { - Assert.assertEquals("John Smith", AuthorList.fixAuthorFirstNameFirst("John Smith")); + assertEquals("John Smith", AuthorList.fixAuthorFirstNameFirst("John Smith")); - Assert.assertEquals("John Smith and Peter Black Brown", AuthorList + assertEquals("John Smith and Peter Black Brown", AuthorList .fixAuthorFirstNameFirst("John Smith and Black Brown, Peter")); - Assert.assertEquals("John von Neumann and John Smith and Peter Black Brown", AuthorList + assertEquals("John von Neumann and John Smith and Peter Black Brown", AuthorList .fixAuthorFirstNameFirst("John von Neumann and John Smith and Black Brown, Peter")); - Assert.assertEquals("First von Last, Jr. III", AuthorList + assertEquals("First von Last, Jr. III", AuthorList .fixAuthorFirstNameFirst("von Last, Jr. III, First")); // Check caching - Assert.assertTrue(AuthorList + assertTrue(AuthorList .fixAuthorFirstNameFirst("John von Neumann and John Smith and Black Brown, Peter").equals(AuthorList .fixAuthorFirstNameFirst("John von Neumann and John Smith and Black Brown, Peter"))); @@ -126,11 +130,11 @@ public void testFixAuthorFirstNameFirst() { @Test public void testFixAuthorLastNameFirstCommasNoComma() { // No commas before and - Assert.assertEquals("", AuthorList.fixAuthorLastNameFirstCommas("", true, false)); - Assert.assertEquals("", AuthorList.fixAuthorLastNameFirstCommas("", false, false)); + assertEquals("", AuthorList.fixAuthorLastNameFirstCommas("", true, false)); + assertEquals("", AuthorList.fixAuthorLastNameFirstCommas("", false, false)); - Assert.assertEquals("Smith, John", AuthorList.fixAuthorLastNameFirstCommas("John Smith", false, false)); - Assert.assertEquals("Smith, J.", AuthorList.fixAuthorLastNameFirstCommas("John Smith", true, false)); + assertEquals("Smith, John", AuthorList.fixAuthorLastNameFirstCommas("John Smith", false, false)); + assertEquals("Smith, J.", AuthorList.fixAuthorLastNameFirstCommas("John Smith", true, false)); String a = AuthorList.fixAuthorLastNameFirstCommas("John von Neumann and John Smith and Black Brown, Peter", true, false); @@ -138,32 +142,32 @@ public void testFixAuthorLastNameFirstCommasNoComma() { "John von Neumann and John Smith and Black Brown, Peter", true, false); // Check caching - Assert.assertEquals(a, b); - Assert.assertTrue(a.equals(b)); + assertEquals(a, b); + assertTrue(a.equals(b)); - Assert.assertEquals("Smith, John and Black Brown, Peter", + assertEquals("Smith, John and Black Brown, Peter", AuthorList.fixAuthorLastNameFirstCommas("John Smith and Black Brown, Peter", false, false)); - Assert.assertEquals("Smith, J. and Black Brown, P.", + assertEquals("Smith, J. and Black Brown, P.", AuthorList.fixAuthorLastNameFirstCommas("John Smith and Black Brown, Peter", true, false)); - Assert.assertEquals("von Neumann, John, Smith, John and Black Brown, Peter", AuthorList + assertEquals("von Neumann, John, Smith, John and Black Brown, Peter", AuthorList .fixAuthorLastNameFirstCommas("John von Neumann and John Smith and Black Brown, Peter", false, false)); - Assert.assertEquals("von Neumann, J., Smith, J. and Black Brown, P.", AuthorList + assertEquals("von Neumann, J., Smith, J. and Black Brown, P.", AuthorList .fixAuthorLastNameFirstCommas("John von Neumann and John Smith and Black Brown, Peter", true, false)); - Assert.assertEquals("von Neumann, J. P.", + assertEquals("von Neumann, J. P.", AuthorList.fixAuthorLastNameFirstCommas("John Peter von Neumann", true, false)); } @Test public void testFixAuthorLastNameFirstCommasOxfordComma() { // Oxford Commas - Assert.assertEquals("", AuthorList.fixAuthorLastNameFirstCommas("", true, true)); - Assert.assertEquals("", AuthorList.fixAuthorLastNameFirstCommas("", false, true)); + assertEquals("", AuthorList.fixAuthorLastNameFirstCommas("", true, true)); + assertEquals("", AuthorList.fixAuthorLastNameFirstCommas("", false, true)); - Assert.assertEquals("Smith, John", AuthorList.fixAuthorLastNameFirstCommas("John Smith", + assertEquals("Smith, John", AuthorList.fixAuthorLastNameFirstCommas("John Smith", false, true)); - Assert.assertEquals("Smith, J.", AuthorList.fixAuthorLastNameFirstCommas("John Smith", true, + assertEquals("Smith, J.", AuthorList.fixAuthorLastNameFirstCommas("John Smith", true, true)); String a = AuthorList.fixAuthorLastNameFirstCommas( @@ -171,22 +175,22 @@ public void testFixAuthorLastNameFirstCommasOxfordComma() { String b = AuthorList.fixAuthorLastNameFirstCommas("John von Neumann and John Smith and Black Brown, Peter", true, true); // Check caching - Assert.assertEquals(a, b); - Assert.assertTrue(a.equals(b)); + assertEquals(a, b); + assertTrue(a.equals(b)); - Assert.assertEquals("Smith, John and Black Brown, Peter", AuthorList + assertEquals("Smith, John and Black Brown, Peter", AuthorList .fixAuthorLastNameFirstCommas("John Smith and Black Brown, Peter", false, true)); - Assert.assertEquals("Smith, J. and Black Brown, P.", AuthorList.fixAuthorLastNameFirstCommas( + assertEquals("Smith, J. and Black Brown, P.", AuthorList.fixAuthorLastNameFirstCommas( "John Smith and Black Brown, Peter", true, true)); - Assert.assertEquals("von Neumann, John, Smith, John, and Black Brown, Peter", AuthorList + assertEquals("von Neumann, John, Smith, John, and Black Brown, Peter", AuthorList .fixAuthorLastNameFirstCommas( "John von Neumann and John Smith and Black Brown, Peter", false, true)); - Assert.assertEquals("von Neumann, J., Smith, J., and Black Brown, P.", AuthorList + assertEquals("von Neumann, J., Smith, J., and Black Brown, P.", AuthorList .fixAuthorLastNameFirstCommas( "John von Neumann and John Smith and Black Brown, Peter", true, true)); - Assert.assertEquals("von Neumann, J. P.", AuthorList.fixAuthorLastNameFirstCommas( + assertEquals("von Neumann, J. P.", AuthorList.fixAuthorLastNameFirstCommas( "John Peter von Neumann", true, true)); } @@ -195,53 +199,53 @@ public void testFixAuthorLastNameFirst() { // Test helper method - Assert.assertEquals("Smith, John", AuthorList.fixAuthorLastNameFirst("John Smith")); + assertEquals("Smith, John", AuthorList.fixAuthorLastNameFirst("John Smith")); - Assert.assertEquals("Smith, John and Black Brown, Peter", AuthorList + assertEquals("Smith, John and Black Brown, Peter", AuthorList .fixAuthorLastNameFirst("John Smith and Black Brown, Peter")); - Assert.assertEquals("von Neumann, John and Smith, John and Black Brown, Peter", AuthorList + assertEquals("von Neumann, John and Smith, John and Black Brown, Peter", AuthorList .fixAuthorLastNameFirst("John von Neumann and John Smith and Black Brown, Peter")); - Assert.assertEquals("von Last, Jr, First", AuthorList + assertEquals("von Last, Jr, First", AuthorList .fixAuthorLastNameFirst("von Last, Jr ,First")); - Assert.assertTrue(AuthorList + assertTrue(AuthorList .fixAuthorLastNameFirst("John von Neumann and John Smith and Black Brown, Peter").equals(AuthorList .fixAuthorLastNameFirst("John von Neumann and John Smith and Black Brown, Peter"))); // Test Abbreviation == false - Assert.assertEquals("Smith, John", AuthorList.fixAuthorLastNameFirst("John Smith", false)); + assertEquals("Smith, John", AuthorList.fixAuthorLastNameFirst("John Smith", false)); - Assert.assertEquals("Smith, John and Black Brown, Peter", AuthorList.fixAuthorLastNameFirst( + assertEquals("Smith, John and Black Brown, Peter", AuthorList.fixAuthorLastNameFirst( "John Smith and Black Brown, Peter", false)); - Assert.assertEquals("von Neumann, John and Smith, John and Black Brown, Peter", AuthorList + assertEquals("von Neumann, John and Smith, John and Black Brown, Peter", AuthorList .fixAuthorLastNameFirst("John von Neumann and John Smith and Black Brown, Peter", false)); - Assert.assertEquals("von Last, Jr, First", AuthorList.fixAuthorLastNameFirst( + assertEquals("von Last, Jr, First", AuthorList.fixAuthorLastNameFirst( "von Last, Jr ,First", false)); - Assert.assertTrue(AuthorList.fixAuthorLastNameFirst( + assertTrue(AuthorList.fixAuthorLastNameFirst( "John von Neumann and John Smith and Black Brown, Peter", false).equals( AuthorList .fixAuthorLastNameFirst("John von Neumann and John Smith and Black Brown, Peter", false))); // Test Abbreviate == true - Assert.assertEquals("Smith, J.", AuthorList.fixAuthorLastNameFirst("John Smith", true)); + assertEquals("Smith, J.", AuthorList.fixAuthorLastNameFirst("John Smith", true)); - Assert.assertEquals("Smith, J. and Black Brown, P.", AuthorList.fixAuthorLastNameFirst( + assertEquals("Smith, J. and Black Brown, P.", AuthorList.fixAuthorLastNameFirst( "John Smith and Black Brown, Peter", true)); - Assert.assertEquals("von Neumann, J. and Smith, J. and Black Brown, P.", + assertEquals("von Neumann, J. and Smith, J. and Black Brown, P.", AuthorList.fixAuthorLastNameFirst( "John von Neumann and John Smith and Black Brown, Peter", true)); - Assert.assertEquals("von Last, Jr, F.", AuthorList.fixAuthorLastNameFirst("von Last, Jr ,First", + assertEquals("von Last, Jr, F.", AuthorList.fixAuthorLastNameFirst("von Last, Jr ,First", true)); - Assert.assertTrue(AuthorList.fixAuthorLastNameFirst( + assertTrue(AuthorList.fixAuthorLastNameFirst( "John von Neumann and John Smith and Black Brown, Peter", true).equals( AuthorList .fixAuthorLastNameFirst("John von Neumann and John Smith and Black Brown, Peter", true))); @@ -252,39 +256,39 @@ public void testFixAuthorLastNameFirst() { public void testFixAuthorLastNameOnlyCommas() { // No comma before and - Assert.assertEquals("", AuthorList.fixAuthorLastNameOnlyCommas("", false)); - Assert.assertEquals("Smith", AuthorList.fixAuthorLastNameOnlyCommas("John Smith", false)); - Assert.assertEquals("Smith", AuthorList.fixAuthorLastNameOnlyCommas("Smith, Jr, John", false)); + assertEquals("", AuthorList.fixAuthorLastNameOnlyCommas("", false)); + assertEquals("Smith", AuthorList.fixAuthorLastNameOnlyCommas("John Smith", false)); + assertEquals("Smith", AuthorList.fixAuthorLastNameOnlyCommas("Smith, Jr, John", false)); - Assert.assertTrue(AuthorList.fixAuthorLastNameOnlyCommas( + assertTrue(AuthorList.fixAuthorLastNameOnlyCommas( "John von Neumann and John Smith and Black Brown, Peter", false).equals( AuthorList .fixAuthorLastNameOnlyCommas("John von Neumann and John Smith and Black Brown, Peter", false))); - Assert.assertEquals("von Neumann, Smith and Black Brown", AuthorList + assertEquals("von Neumann, Smith and Black Brown", AuthorList .fixAuthorLastNameOnlyCommas( "John von Neumann and John Smith and Black Brown, Peter", false)); // Oxford Comma - Assert.assertEquals("", AuthorList.fixAuthorLastNameOnlyCommas("", true)); - Assert.assertEquals("Smith", AuthorList.fixAuthorLastNameOnlyCommas("John Smith", true)); - Assert.assertEquals("Smith", AuthorList.fixAuthorLastNameOnlyCommas("Smith, Jr, John", true)); + assertEquals("", AuthorList.fixAuthorLastNameOnlyCommas("", true)); + assertEquals("Smith", AuthorList.fixAuthorLastNameOnlyCommas("John Smith", true)); + assertEquals("Smith", AuthorList.fixAuthorLastNameOnlyCommas("Smith, Jr, John", true)); - Assert.assertTrue(AuthorList.fixAuthorLastNameOnlyCommas( + assertTrue(AuthorList.fixAuthorLastNameOnlyCommas( "John von Neumann and John Smith and Black Brown, Peter", true).equals( AuthorList .fixAuthorLastNameOnlyCommas("John von Neumann and John Smith and Black Brown, Peter", true))); - Assert.assertEquals("von Neumann, Smith, and Black Brown", AuthorList + assertEquals("von Neumann, Smith, and Black Brown", AuthorList .fixAuthorLastNameOnlyCommas( "John von Neumann and John Smith and Black Brown, Peter", true)); } @Test public void testFixAuthorForAlphabetization() { - Assert.assertEquals("Smith, J.", AuthorList.fixAuthorForAlphabetization("John Smith")); - Assert.assertEquals("Neumann, J.", AuthorList.fixAuthorForAlphabetization("John von Neumann")); - Assert.assertEquals("Neumann, J.", AuthorList.fixAuthorForAlphabetization("J. von Neumann")); - Assert.assertEquals( + assertEquals("Smith, J.", AuthorList.fixAuthorForAlphabetization("John Smith")); + assertEquals("Neumann, J.", AuthorList.fixAuthorForAlphabetization("John von Neumann")); + assertEquals("Neumann, J.", AuthorList.fixAuthorForAlphabetization("J. von Neumann")); + assertEquals( "Neumann, J. and Smith, J. and Black Brown, Jr., P.", AuthorList .fixAuthorForAlphabetization("John von Neumann and John Smith and de Black Brown, Jr., Peter")); @@ -293,75 +297,74 @@ public void testFixAuthorForAlphabetization() { @Test public void testSize() { - Assert.assertEquals(0, AuthorListTest.size("")); - Assert.assertEquals(1, AuthorListTest.size("Bar")); - Assert.assertEquals(1, AuthorListTest.size("Foo Bar")); - Assert.assertEquals(1, AuthorListTest.size("Foo von Bar")); - Assert.assertEquals(1, AuthorListTest.size("von Bar, Foo")); - Assert.assertEquals(1, AuthorListTest.size("Bar, Foo")); - Assert.assertEquals(1, AuthorListTest.size("Bar, Jr., Foo")); - Assert.assertEquals(1, AuthorListTest.size("Bar, Foo")); - Assert.assertEquals(2, AuthorListTest.size("John Neumann and Foo Bar")); - Assert.assertEquals(2, AuthorListTest.size("John von Neumann and Bar, Jr, Foo")); + assertEquals(0, AuthorListTest.size("")); + assertEquals(1, AuthorListTest.size("Bar")); + assertEquals(1, AuthorListTest.size("Foo Bar")); + assertEquals(1, AuthorListTest.size("Foo von Bar")); + assertEquals(1, AuthorListTest.size("von Bar, Foo")); + assertEquals(1, AuthorListTest.size("Bar, Foo")); + assertEquals(1, AuthorListTest.size("Bar, Jr., Foo")); + assertEquals(1, AuthorListTest.size("Bar, Foo")); + assertEquals(2, AuthorListTest.size("John Neumann and Foo Bar")); + assertEquals(2, AuthorListTest.size("John von Neumann and Bar, Jr, Foo")); - Assert.assertEquals(3, AuthorListTest.size("John von Neumann and John Smith and Black Brown, Peter")); + assertEquals(3, AuthorListTest.size("John von Neumann and John Smith and Black Brown, Peter")); StringBuilder s = new StringBuilder("John von Neumann"); for (int i = 0; i < 25; i++) { - Assert.assertEquals(i + 1, AuthorListTest.size(s.toString())); + assertEquals(i + 1, AuthorListTest.size(s.toString())); s.append(" and Albert Einstein"); } } @Test public void testIsEmpty() { - - Assert.assertTrue(AuthorList.parse("").isEmpty()); - Assert.assertFalse(AuthorList.parse("Bar").isEmpty()); + assertTrue(AuthorList.parse("").isEmpty()); + assertFalse(AuthorList.parse("Bar").isEmpty()); } - @Test(expected = Exception.class) + @Test public void testGetEmptyAuthor() { - AuthorList.parse("").getAuthor(0); - Assert.fail(); + assertThrows(Exception.class, () -> AuthorList.parse("").getAuthor(0)); + } @Test public void testGetAuthor() { Author author = AuthorList.parse("John Smith and von Neumann, Jr, John").getAuthor(0); - Assert.assertEquals(Optional.of("John"), author.getFirst()); - Assert.assertEquals(Optional.of("J."), author.getFirstAbbr()); - Assert.assertEquals("John Smith", author.getFirstLast(false)); - Assert.assertEquals("J. Smith", author.getFirstLast(true)); - Assert.assertEquals(Optional.empty(), author.getJr()); - Assert.assertEquals(Optional.of("Smith"), author.getLast()); - Assert.assertEquals("Smith, John", author.getLastFirst(false)); - Assert.assertEquals("Smith, J.", author.getLastFirst(true)); - Assert.assertEquals("Smith", author.getLastOnly()); - Assert.assertEquals("Smith, J.", author.getNameForAlphabetization()); - Assert.assertEquals(Optional.empty(), author.getVon()); + assertEquals(Optional.of("John"), author.getFirst()); + assertEquals(Optional.of("J."), author.getFirstAbbr()); + assertEquals("John Smith", author.getFirstLast(false)); + assertEquals("J. Smith", author.getFirstLast(true)); + assertEquals(Optional.empty(), author.getJr()); + assertEquals(Optional.of("Smith"), author.getLast()); + assertEquals("Smith, John", author.getLastFirst(false)); + assertEquals("Smith, J.", author.getLastFirst(true)); + assertEquals("Smith", author.getLastOnly()); + assertEquals("Smith, J.", author.getNameForAlphabetization()); + assertEquals(Optional.empty(), author.getVon()); author = AuthorList.parse("Peter Black Brown").getAuthor(0); - Assert.assertEquals(Optional.of("Peter Black"), author.getFirst()); - Assert.assertEquals(Optional.of("P. B."), author.getFirstAbbr()); - Assert.assertEquals("Peter Black Brown", author.getFirstLast(false)); - Assert.assertEquals("P. B. Brown", author.getFirstLast(true)); - Assert.assertEquals(Optional.empty(), author.getJr()); - Assert.assertEquals(Optional.empty(), author.getVon()); + assertEquals(Optional.of("Peter Black"), author.getFirst()); + assertEquals(Optional.of("P. B."), author.getFirstAbbr()); + assertEquals("Peter Black Brown", author.getFirstLast(false)); + assertEquals("P. B. Brown", author.getFirstLast(true)); + assertEquals(Optional.empty(), author.getJr()); + assertEquals(Optional.empty(), author.getVon()); author = AuthorList.parse("John Smith and von Neumann, Jr, John").getAuthor(1); - Assert.assertEquals(Optional.of("John"), author.getFirst()); - Assert.assertEquals(Optional.of("J."), author.getFirstAbbr()); - Assert.assertEquals("John von Neumann, Jr", author.getFirstLast(false)); - Assert.assertEquals("J. von Neumann, Jr", author.getFirstLast(true)); - Assert.assertEquals(Optional.of("Jr"), author.getJr()); - Assert.assertEquals(Optional.of("Neumann"), author.getLast()); - Assert.assertEquals("von Neumann, Jr, John", author.getLastFirst(false)); - Assert.assertEquals("von Neumann, Jr, J.", author.getLastFirst(true)); - Assert.assertEquals("von Neumann", author.getLastOnly()); - Assert.assertEquals("Neumann, Jr, J.", author.getNameForAlphabetization()); - Assert.assertEquals(Optional.of("von"), author.getVon()); + assertEquals(Optional.of("John"), author.getFirst()); + assertEquals(Optional.of("J."), author.getFirstAbbr()); + assertEquals("John von Neumann, Jr", author.getFirstLast(false)); + assertEquals("J. von Neumann, Jr", author.getFirstLast(true)); + assertEquals(Optional.of("Jr"), author.getJr()); + assertEquals(Optional.of("Neumann"), author.getLast()); + assertEquals("von Neumann, Jr, John", author.getLastFirst(false)); + assertEquals("von Neumann, Jr, J.", author.getLastFirst(true)); + assertEquals("von Neumann", author.getLastOnly()); + assertEquals("Neumann, Jr, J.", author.getNameForAlphabetization()); + assertEquals(Optional.of("von"), author.getVon()); } @@ -369,65 +372,65 @@ public void testGetAuthor() { public void testCompanyAuthor() { Author author = AuthorList.parse("{JabRef Developers}").getAuthor(0); Author expected = new Author(null, null, null, "JabRef Developers", null); - Assert.assertEquals(expected, author); + assertEquals(expected, author); } @Test public void testCompanyAuthorWithLowerCaseWord() { Author author = AuthorList.parse("{JabRef Developers on Fire}").getAuthor(0); Author expected = new Author(null, null, null, "JabRef Developers on Fire", null); - Assert.assertEquals(expected, author); + assertEquals(expected, author); } @Test public void testAbbreviationWithRelax() { Author author = AuthorList.parse("{\\relax Ch}ristoph Cholera").getAuthor(0); Author expected = new Author("{\\relax Ch}ristoph", "{\\relax Ch}.", null, "Cholera", null); - Assert.assertEquals(expected, author); + assertEquals(expected, author); } @Test public void testGetAuthorsNatbib() { - Assert.assertEquals("", AuthorList.parse("").getAsNatbib()); - Assert.assertEquals("Smith", AuthorList.parse("John Smith").getAsNatbib()); - Assert.assertEquals("Smith and Black Brown", AuthorList.parse( + assertEquals("", AuthorList.parse("").getAsNatbib()); + assertEquals("Smith", AuthorList.parse("John Smith").getAsNatbib()); + assertEquals("Smith and Black Brown", AuthorList.parse( "John Smith and Black Brown, Peter").getAsNatbib()); - Assert.assertEquals("von Neumann et al.", AuthorList.parse( + assertEquals("von Neumann et al.", AuthorList.parse( "John von Neumann and John Smith and Black Brown, Peter").getAsNatbib()); /* * [ 1465610 ] (Double-)Names containing hyphen (-) not handled correctly */ - Assert.assertEquals("Last-Name et al.", AuthorList.parse( + assertEquals("Last-Name et al.", AuthorList.parse( "First Second Last-Name" + " and John Smith and Black Brown, Peter").getAsNatbib()); // Test caching AuthorList al = AuthorList .parse("John von Neumann and John Smith and Black Brown, Peter"); - Assert.assertTrue(al.getAsNatbib().equals(al.getAsNatbib())); + assertTrue(al.getAsNatbib().equals(al.getAsNatbib())); } @Test public void testGetAuthorsLastOnly() { // No comma before and - Assert.assertEquals("", AuthorList.parse("").getAsLastNames(false)); - Assert.assertEquals("Smith", AuthorList.parse("John Smith").getAsLastNames(false)); - Assert.assertEquals("Smith", AuthorList.parse("Smith, Jr, John").getAsLastNames( + assertEquals("", AuthorList.parse("").getAsLastNames(false)); + assertEquals("Smith", AuthorList.parse("John Smith").getAsLastNames(false)); + assertEquals("Smith", AuthorList.parse("Smith, Jr, John").getAsLastNames( false)); - Assert.assertEquals("von Neumann, Smith and Black Brown", AuthorList.parse( + assertEquals("von Neumann, Smith and Black Brown", AuthorList.parse( "John von Neumann and John Smith and Black Brown, Peter").getAsLastNames(false)); // Oxford comma - Assert.assertEquals("", AuthorList.parse("").getAsLastNames(true)); - Assert.assertEquals("Smith", AuthorList.parse("John Smith").getAsLastNames(true)); - Assert.assertEquals("Smith", AuthorList.parse("Smith, Jr, John").getAsLastNames( + assertEquals("", AuthorList.parse("").getAsLastNames(true)); + assertEquals("Smith", AuthorList.parse("John Smith").getAsLastNames(true)); + assertEquals("Smith", AuthorList.parse("Smith, Jr, John").getAsLastNames( true)); - Assert.assertEquals("von Neumann, Smith, and Black Brown", AuthorList.parse( + assertEquals("von Neumann, Smith, and Black Brown", AuthorList.parse( "John von Neumann and John Smith and Black Brown, Peter").getAsLastNames(true)); - Assert.assertEquals("von Neumann and Smith", + assertEquals("von Neumann and Smith", AuthorList.parse("John von Neumann and John Smith").getAsLastNames(false)); } @@ -437,26 +440,26 @@ public void testGetAuthorsLastFirstNoComma() { AuthorList al; al = AuthorList.parse(""); - Assert.assertEquals("", al.getAsLastFirstNames(true, false)); - Assert.assertEquals("", al.getAsLastFirstNames(false, false)); + assertEquals("", al.getAsLastFirstNames(true, false)); + assertEquals("", al.getAsLastFirstNames(false, false)); al = AuthorList.parse("John Smith"); - Assert.assertEquals("Smith, John", al.getAsLastFirstNames(false, false)); - Assert.assertEquals("Smith, J.", al.getAsLastFirstNames(true, false)); + assertEquals("Smith, John", al.getAsLastFirstNames(false, false)); + assertEquals("Smith, J.", al.getAsLastFirstNames(true, false)); al = AuthorList.parse("John Smith and Black Brown, Peter"); - Assert.assertEquals("Smith, John and Black Brown, Peter", al.getAsLastFirstNames(false, false)); - Assert.assertEquals("Smith, J. and Black Brown, P.", al.getAsLastFirstNames(true, false)); + assertEquals("Smith, John and Black Brown, Peter", al.getAsLastFirstNames(false, false)); + assertEquals("Smith, J. and Black Brown, P.", al.getAsLastFirstNames(true, false)); al = AuthorList.parse("John von Neumann and John Smith and Black Brown, Peter"); // Method description is different than code -> additional comma // there - Assert.assertEquals("von Neumann, John, Smith, John and Black Brown, Peter", + assertEquals("von Neumann, John, Smith, John and Black Brown, Peter", al.getAsLastFirstNames(false, false)); - Assert.assertEquals("von Neumann, J., Smith, J. and Black Brown, P.", al.getAsLastFirstNames(true, false)); + assertEquals("von Neumann, J., Smith, J. and Black Brown, P.", al.getAsLastFirstNames(true, false)); al = AuthorList.parse("John Peter von Neumann"); - Assert.assertEquals("von Neumann, J. P.", al.getAsLastFirstNames(true, false)); + assertEquals("von Neumann, J. P.", al.getAsLastFirstNames(true, false)); } @Test @@ -465,46 +468,46 @@ public void testGetAuthorsLastFirstOxfordComma() { AuthorList al; al = AuthorList.parse(""); - Assert.assertEquals("", al.getAsLastFirstNames(true, true)); - Assert.assertEquals("", al.getAsLastFirstNames(false, true)); + assertEquals("", al.getAsLastFirstNames(true, true)); + assertEquals("", al.getAsLastFirstNames(false, true)); al = AuthorList.parse("John Smith"); - Assert.assertEquals("Smith, John", al.getAsLastFirstNames(false, true)); - Assert.assertEquals("Smith, J.", al.getAsLastFirstNames(true, true)); + assertEquals("Smith, John", al.getAsLastFirstNames(false, true)); + assertEquals("Smith, J.", al.getAsLastFirstNames(true, true)); al = AuthorList.parse("John Smith and Black Brown, Peter"); - Assert.assertEquals("Smith, John and Black Brown, Peter", al.getAsLastFirstNames(false, true)); - Assert.assertEquals("Smith, J. and Black Brown, P.", al.getAsLastFirstNames(true, true)); + assertEquals("Smith, John and Black Brown, Peter", al.getAsLastFirstNames(false, true)); + assertEquals("Smith, J. and Black Brown, P.", al.getAsLastFirstNames(true, true)); al = AuthorList.parse("John von Neumann and John Smith and Black Brown, Peter"); - Assert.assertEquals("von Neumann, John, Smith, John, and Black Brown, Peter", al + assertEquals("von Neumann, John, Smith, John, and Black Brown, Peter", al .getAsLastFirstNames(false, true)); - Assert.assertEquals("von Neumann, J., Smith, J., and Black Brown, P.", al.getAsLastFirstNames( + assertEquals("von Neumann, J., Smith, J., and Black Brown, P.", al.getAsLastFirstNames( true, true)); al = AuthorList.parse("John Peter von Neumann"); - Assert.assertEquals("von Neumann, J. P.", al.getAsLastFirstNames(true, true)); + assertEquals("von Neumann, J. P.", al.getAsLastFirstNames(true, true)); } @Test public void testGetAuthorsLastFirstAnds() { - Assert.assertEquals("Smith, John", AuthorList.parse("John Smith").getAsLastFirstNamesWithAnd( + assertEquals("Smith, John", AuthorList.parse("John Smith").getAsLastFirstNamesWithAnd( false)); - Assert.assertEquals("Smith, John and Black Brown, Peter", AuthorList.parse( + assertEquals("Smith, John and Black Brown, Peter", AuthorList.parse( "John Smith and Black Brown, Peter").getAsLastFirstNamesWithAnd(false)); - Assert.assertEquals("von Neumann, John and Smith, John and Black Brown, Peter", AuthorList + assertEquals("von Neumann, John and Smith, John and Black Brown, Peter", AuthorList .parse("John von Neumann and John Smith and Black Brown, Peter") .getAsLastFirstNamesWithAnd(false)); - Assert.assertEquals("von Last, Jr, First", AuthorList.parse("von Last, Jr ,First") + assertEquals("von Last, Jr, First", AuthorList.parse("von Last, Jr ,First") .getAsLastFirstNamesWithAnd(false)); - Assert.assertEquals("Smith, J.", AuthorList.parse("John Smith").getAsLastFirstNamesWithAnd( + assertEquals("Smith, J.", AuthorList.parse("John Smith").getAsLastFirstNamesWithAnd( true)); - Assert.assertEquals("Smith, J. and Black Brown, P.", AuthorList.parse( + assertEquals("Smith, J. and Black Brown, P.", AuthorList.parse( "John Smith and Black Brown, Peter").getAsLastFirstNamesWithAnd(true)); - Assert.assertEquals("von Neumann, J. and Smith, J. and Black Brown, P.", AuthorList.parse( + assertEquals("von Neumann, J. and Smith, J. and Black Brown, P.", AuthorList.parse( "John von Neumann and John Smith and Black Brown, Peter").getAsLastFirstNamesWithAnd(true)); - Assert.assertEquals("von Last, Jr, F.", AuthorList.parse("von Last, Jr ,First") + assertEquals("von Last, Jr, F.", AuthorList.parse("von Last, Jr ,First") .getAsLastFirstNamesWithAnd(true)); } @@ -512,10 +515,10 @@ public void testGetAuthorsLastFirstAnds() { @Test public void testGetAuthorsLastFirstAndsCaching() { // getAsLastFirstNamesWithAnd caches its results, therefore we call the method twice using the same arguments - Assert.assertEquals("Smith, John", AuthorList.parse("John Smith").getAsLastFirstNamesWithAnd(false)); - Assert.assertEquals("Smith, John", AuthorList.parse("John Smith").getAsLastFirstNamesWithAnd(false)); - Assert.assertEquals("Smith, J.", AuthorList.parse("John Smith").getAsLastFirstNamesWithAnd(true)); - Assert.assertEquals("Smith, J.", AuthorList.parse("John Smith").getAsLastFirstNamesWithAnd(true)); + assertEquals("Smith, John", AuthorList.parse("John Smith").getAsLastFirstNamesWithAnd(false)); + assertEquals("Smith, John", AuthorList.parse("John Smith").getAsLastFirstNamesWithAnd(false)); + assertEquals("Smith, J.", AuthorList.parse("John Smith").getAsLastFirstNamesWithAnd(true)); + assertEquals("Smith, J.", AuthorList.parse("John Smith").getAsLastFirstNamesWithAnd(true)); } @Test @@ -524,79 +527,79 @@ public void testGetAuthorsFirstFirst() { AuthorList al; al = AuthorList.parse(""); - Assert.assertEquals("", al.getAsFirstLastNames(true, false)); - Assert.assertEquals("", al.getAsFirstLastNames(false, false)); - Assert.assertEquals("", al.getAsFirstLastNames(true, true)); - Assert.assertEquals("", al.getAsFirstLastNames(false, true)); + assertEquals("", al.getAsFirstLastNames(true, false)); + assertEquals("", al.getAsFirstLastNames(false, false)); + assertEquals("", al.getAsFirstLastNames(true, true)); + assertEquals("", al.getAsFirstLastNames(false, true)); al = AuthorList.parse("John Smith"); - Assert.assertEquals("John Smith", al.getAsFirstLastNames(false, false)); - Assert.assertEquals("J. Smith", al.getAsFirstLastNames(true, false)); - Assert.assertEquals("John Smith", al.getAsFirstLastNames(false, true)); - Assert.assertEquals("J. Smith", al.getAsFirstLastNames(true, true)); + assertEquals("John Smith", al.getAsFirstLastNames(false, false)); + assertEquals("J. Smith", al.getAsFirstLastNames(true, false)); + assertEquals("John Smith", al.getAsFirstLastNames(false, true)); + assertEquals("J. Smith", al.getAsFirstLastNames(true, true)); al = AuthorList.parse("John Smith and Black Brown, Peter"); - Assert.assertEquals("John Smith and Peter Black Brown", al.getAsFirstLastNames(false, false)); - Assert.assertEquals("J. Smith and P. Black Brown", al.getAsFirstLastNames(true, false)); - Assert.assertEquals("John Smith and Peter Black Brown", al.getAsFirstLastNames(false, true)); - Assert.assertEquals("J. Smith and P. Black Brown", al.getAsFirstLastNames(true, true)); + assertEquals("John Smith and Peter Black Brown", al.getAsFirstLastNames(false, false)); + assertEquals("J. Smith and P. Black Brown", al.getAsFirstLastNames(true, false)); + assertEquals("John Smith and Peter Black Brown", al.getAsFirstLastNames(false, true)); + assertEquals("J. Smith and P. Black Brown", al.getAsFirstLastNames(true, true)); al = AuthorList.parse("John von Neumann and John Smith and Black Brown, Peter"); - Assert.assertEquals("John von Neumann, John Smith and Peter Black Brown", al.getAsFirstLastNames( + assertEquals("John von Neumann, John Smith and Peter Black Brown", al.getAsFirstLastNames( false, false)); - Assert.assertEquals("J. von Neumann, J. Smith and P. Black Brown", al.getAsFirstLastNames(true, + assertEquals("J. von Neumann, J. Smith and P. Black Brown", al.getAsFirstLastNames(true, false)); - Assert.assertEquals("John von Neumann, John Smith, and Peter Black Brown", al + assertEquals("John von Neumann, John Smith, and Peter Black Brown", al .getAsFirstLastNames(false, true)); - Assert.assertEquals("J. von Neumann, J. Smith, and P. Black Brown", al.getAsFirstLastNames(true, + assertEquals("J. von Neumann, J. Smith, and P. Black Brown", al.getAsFirstLastNames(true, true)); al = AuthorList.parse("John Peter von Neumann"); - Assert.assertEquals("John Peter von Neumann", al.getAsFirstLastNames(false, false)); - Assert.assertEquals("John Peter von Neumann", al.getAsFirstLastNames(false, true)); - Assert.assertEquals("J. P. von Neumann", al.getAsFirstLastNames(true, false)); - Assert.assertEquals("J. P. von Neumann", al.getAsFirstLastNames(true, true)); + assertEquals("John Peter von Neumann", al.getAsFirstLastNames(false, false)); + assertEquals("John Peter von Neumann", al.getAsFirstLastNames(false, true)); + assertEquals("J. P. von Neumann", al.getAsFirstLastNames(true, false)); + assertEquals("J. P. von Neumann", al.getAsFirstLastNames(true, true)); } @Test public void testGetAuthorsFirstFirstAnds() { - Assert.assertEquals("John Smith", AuthorList.parse("John Smith") + assertEquals("John Smith", AuthorList.parse("John Smith") .getAsFirstLastNamesWithAnd()); - Assert.assertEquals("John Smith and Peter Black Brown", AuthorList.parse( + assertEquals("John Smith and Peter Black Brown", AuthorList.parse( "John Smith and Black Brown, Peter").getAsFirstLastNamesWithAnd()); - Assert.assertEquals("John von Neumann and John Smith and Peter Black Brown", AuthorList + assertEquals("John von Neumann and John Smith and Peter Black Brown", AuthorList .parse("John von Neumann and John Smith and Black Brown, Peter") .getAsFirstLastNamesWithAnd()); - Assert.assertEquals("First von Last, Jr. III", AuthorList + assertEquals("First von Last, Jr. III", AuthorList .parse("von Last, Jr. III, First").getAsFirstLastNamesWithAnd()); } @Test public void testGetAuthorsForAlphabetization() { - Assert.assertEquals("Smith, J.", AuthorList.parse("John Smith") + assertEquals("Smith, J.", AuthorList.parse("John Smith") .getForAlphabetization()); - Assert.assertEquals("Neumann, J.", AuthorList.parse("John von Neumann") + assertEquals("Neumann, J.", AuthorList.parse("John von Neumann") .getForAlphabetization()); - Assert.assertEquals("Neumann, J.", AuthorList.parse("J. von Neumann") + assertEquals("Neumann, J.", AuthorList.parse("J. von Neumann") .getForAlphabetization()); - Assert.assertEquals("Neumann, J. and Smith, J. and Black Brown, Jr., P.", AuthorList + assertEquals("Neumann, J. and Smith, J. and Black Brown, Jr., P.", AuthorList .parse("John von Neumann and John Smith and de Black Brown, Jr., Peter") .getForAlphabetization()); } @Test public void testRemoveStartAndEndBraces() { - Assert.assertEquals("{A}bbb{c}", AuthorList.parse("{A}bbb{c}").getAsLastNames(false)); - Assert.assertEquals("Vall{\\'e}e Poussin", AuthorList.parse("{Vall{\\'e}e Poussin}").getAsLastNames(false)); - Assert.assertEquals("Poussin", AuthorList.parse("{Vall{\\'e}e} {Poussin}").getAsLastNames(false)); - Assert.assertEquals("Poussin", AuthorList.parse("Vall{\\'e}e Poussin").getAsLastNames(false)); - Assert.assertEquals("Lastname", AuthorList.parse("Firstname {Lastname}").getAsLastNames(false)); - Assert.assertEquals("Firstname Lastname", AuthorList.parse("{Firstname Lastname}").getAsLastNames(false)); + assertEquals("{A}bbb{c}", AuthorList.parse("{A}bbb{c}").getAsLastNames(false)); + assertEquals("Vall{\\'e}e Poussin", AuthorList.parse("{Vall{\\'e}e Poussin}").getAsLastNames(false)); + assertEquals("Poussin", AuthorList.parse("{Vall{\\'e}e} {Poussin}").getAsLastNames(false)); + assertEquals("Poussin", AuthorList.parse("Vall{\\'e}e Poussin").getAsLastNames(false)); + assertEquals("Lastname", AuthorList.parse("Firstname {Lastname}").getAsLastNames(false)); + assertEquals("Firstname Lastname", AuthorList.parse("{Firstname Lastname}").getAsLastNames(false)); } @Test public void createCorrectInitials() { - Assert.assertEquals(Optional.of("J. G."), + assertEquals(Optional.of("J. G."), AuthorList.parse("Hornberg, Johann Gottfried").getAuthor(0).getFirstAbbr()); } @@ -604,50 +607,50 @@ public void createCorrectInitials() { public void parseNameWithBracesAroundFirstName() throws Exception { //TODO: Be more intelligent and abbreviate the first name correctly Author expected = new Author("Tse-tung", "{Tse-tung}.", null, "Mao", null); - Assert.assertEquals(new AuthorList(expected), AuthorList.parse("{Tse-tung} Mao")); + assertEquals(new AuthorList(expected), AuthorList.parse("{Tse-tung} Mao")); } @Test public void parseNameWithBracesAroundLastName() throws Exception { Author expected = new Author("Hans", "H.", null, "van den Bergen", null); - Assert.assertEquals(new AuthorList(expected), AuthorList.parse("{van den Bergen}, Hans")); + assertEquals(new AuthorList(expected), AuthorList.parse("{van den Bergen}, Hans")); } @Test public void parseNameWithHyphenInFirstName() throws Exception { Author expected = new Author("Tse-tung", "T.-t.", null, "Mao", null); - Assert.assertEquals(new AuthorList(expected), AuthorList.parse("Tse-tung Mao")); + assertEquals(new AuthorList(expected), AuthorList.parse("Tse-tung Mao")); } @Test public void parseNameWithHyphenInLastName() throws Exception { Author expected = new Author("Firstname", "F.", null, "Bailey-Jones", null); - Assert.assertEquals(new AuthorList(expected), AuthorList.parse("Firstname Bailey-Jones")); + assertEquals(new AuthorList(expected), AuthorList.parse("Firstname Bailey-Jones")); } @Test public void parseNameWithHyphenInLastNameWithInitials() throws Exception { Author expected = new Author("E. S.", "E. S.", null, "El-{M}allah", null); - Assert.assertEquals(new AuthorList(expected), AuthorList.parse("E. S. El-{M}allah")); + assertEquals(new AuthorList(expected), AuthorList.parse("E. S. El-{M}allah")); } @Test public void parseNameWithHyphenInLastNameWithEscaped() throws Exception { Author expected = new Author("E. S.", "E. S.", null, "{K}ent-{B}oswell", null); - Assert.assertEquals(new AuthorList(expected), AuthorList.parse("E. S. {K}ent-{B}oswell")); + assertEquals(new AuthorList(expected), AuthorList.parse("E. S. {K}ent-{B}oswell")); } @Test public void parseNameWithHyphenInLastNameWhenLastNameGivenFirst() throws Exception { // TODO: Fix abbreviation to be "A." Author expected = new Author("ʿAbdallāh", "ʿ.", null, "al-Ṣāliḥ", null); - Assert.assertEquals(new AuthorList(expected), AuthorList.parse("al-Ṣāliḥ, ʿAbdallāh")); + assertEquals(new AuthorList(expected), AuthorList.parse("al-Ṣāliḥ, ʿAbdallāh")); } @Test public void parseNameWithBraces() throws Exception { Author expected = new Author("H{e}lene", "H.", null, "Fiaux", null); - Assert.assertEquals(new AuthorList(expected), AuthorList.parse("H{e}lene Fiaux")); + assertEquals(new AuthorList(expected), AuthorList.parse("H{e}lene Fiaux")); } /** @@ -656,16 +659,16 @@ public void parseNameWithBraces() throws Exception { @Test public void correctNamesWithOneComma() throws Exception { Author expected = new Author("Alexander der Große", "A. d. G.", null, "Canon der Barbar", null); - Assert.assertEquals(new AuthorList(expected), AuthorList.parse("Canon der Barbar, Alexander der Große")); + assertEquals(new AuthorList(expected), AuthorList.parse("Canon der Barbar, Alexander der Große")); expected = new Author("Alexander H. G.", "A. H. G.", null, "Rinnooy Kan", null); - Assert.assertEquals(new AuthorList(expected), AuthorList.parse("Rinnooy Kan, Alexander H. G.")); + assertEquals(new AuthorList(expected), AuthorList.parse("Rinnooy Kan, Alexander H. G.")); expected = new Author("Alexander Hendrik George", "A. H. G.", null, "Rinnooy Kan", null); - Assert.assertEquals(new AuthorList(expected), AuthorList.parse("Rinnooy Kan, Alexander Hendrik George")); + assertEquals(new AuthorList(expected), AuthorList.parse("Rinnooy Kan, Alexander Hendrik George")); expected = new Author("José María", "J. M.", null, "Rodriguez Fernandez", null); - Assert.assertEquals(new AuthorList(expected), AuthorList.parse("Rodriguez Fernandez, José María")); + assertEquals(new AuthorList(expected), AuthorList.parse("Rodriguez Fernandez, José María")); } } diff --git a/src/test/java/org/jabref/model/entry/BibEntryTest.java b/src/test/java/org/jabref/model/entry/BibEntryTest.java index 48f9b649f31..6e62eff5c77 100644 --- a/src/test/java/org/jabref/model/entry/BibEntryTest.java +++ b/src/test/java/org/jabref/model/entry/BibEntryTest.java @@ -10,8 +10,8 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertThrows; public class BibEntryTest { diff --git a/src/test/java/org/jabref/model/entry/EntryLinkListTest.java b/src/test/java/org/jabref/model/entry/EntryLinkListTest.java index b1381b23fe9..77a5c71d059 100644 --- a/src/test/java/org/jabref/model/entry/EntryLinkListTest.java +++ b/src/test/java/org/jabref/model/entry/EntryLinkListTest.java @@ -8,7 +8,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; public class EntryLinkListTest { diff --git a/src/test/java/org/jabref/model/entry/KeywordTest.java b/src/test/java/org/jabref/model/entry/KeywordTest.java index a5047fa07a9..7496ed23771 100644 --- a/src/test/java/org/jabref/model/entry/KeywordTest.java +++ b/src/test/java/org/jabref/model/entry/KeywordTest.java @@ -5,7 +5,7 @@ import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class KeywordTest { diff --git a/src/test/java/org/jabref/model/strings/StringUtilTest.java b/src/test/java/org/jabref/model/strings/StringUtilTest.java index 1505d9cb9d2..a6fae659433 100644 --- a/src/test/java/org/jabref/model/strings/StringUtilTest.java +++ b/src/test/java/org/jabref/model/strings/StringUtilTest.java @@ -2,11 +2,12 @@ import java.util.Optional; -import org.junit.Test; +import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; public class StringUtilTest { @@ -218,19 +219,19 @@ public void testIntValueOfStartWithZeros() { assertEquals(1234, StringUtil.intValueOf("001234")); } - @Test(expected = NumberFormatException.class) + @Test public void testIntValueOfExceptionIfStringContainsLetter() { - StringUtil.intValueOf("12A2"); + assertThrows(NumberFormatException.class, () -> StringUtil.intValueOf("12A2")); } - @Test(expected = NumberFormatException.class) + @Test public void testIntValueOfExceptionIfStringNull() { - StringUtil.intValueOf(null); + assertThrows(NumberFormatException.class, () -> StringUtil.intValueOf(null)); } - @Test(expected = NumberFormatException.class) + @Test public void testIntValueOfExceptionfIfStringEmpty() { - StringUtil.intValueOf(""); + assertThrows(NumberFormatException.class, () -> StringUtil.intValueOf("")); } @Test From 8c461e2e3b1b40a90c798fd838067dcdbfaa88f3 Mon Sep 17 00:00:00 2001 From: Siedlerchr Date: Fri, 9 Feb 2018 17:08:39 +0100 Subject: [PATCH 17/94] fix somre more test Mock externalFileTypes in importer test --- .../jabref/gui/FindUnlinkedFilesDialog.java | 3 ++- .../importer/EntryFromFileCreatorManager.java | 6 ++--- .../gui/importer/EntryFromPDFCreator.java | 10 ++++---- .../EntryFromFileCreatorManagerTest.java | 23 +++++++++++++++---- .../gui/importer/EntryFromPDFCreatorTest.java | 6 ++++- .../model/entry/identifier/EprintTest.java | 2 ++ 6 files changed, 35 insertions(+), 15 deletions(-) diff --git a/src/main/java/org/jabref/gui/FindUnlinkedFilesDialog.java b/src/main/java/org/jabref/gui/FindUnlinkedFilesDialog.java index 0d4b38b0971..79b5ec468bf 100644 --- a/src/main/java/org/jabref/gui/FindUnlinkedFilesDialog.java +++ b/src/main/java/org/jabref/gui/FindUnlinkedFilesDialog.java @@ -67,6 +67,7 @@ import org.jabref.JabRefExecutorService; import org.jabref.JabRefGUI; import org.jabref.gui.desktop.JabRefDesktop; +import org.jabref.gui.externalfiletype.ExternalFileTypes; import org.jabref.gui.importer.EntryFromFileCreator; import org.jabref.gui.importer.EntryFromFileCreatorManager; import org.jabref.gui.importer.UnlinkedFilesCrawler; @@ -167,7 +168,7 @@ public FindUnlinkedFilesDialog(Frame owner, JabRefFrame frame, BasePanel panel) restoreSizeOfDialog(); databaseContext = panel.getDatabaseContext(); - creatorManager = new EntryFromFileCreatorManager(); + creatorManager = new EntryFromFileCreatorManager(ExternalFileTypes.getInstance()); crawler = new UnlinkedFilesCrawler(databaseContext); lastSelectedDirectory = loadLastSelectedDirectory(); diff --git a/src/main/java/org/jabref/gui/importer/EntryFromFileCreatorManager.java b/src/main/java/org/jabref/gui/importer/EntryFromFileCreatorManager.java index 49afd6f0f6d..f9b83282284 100644 --- a/src/main/java/org/jabref/gui/importer/EntryFromFileCreatorManager.java +++ b/src/main/java/org/jabref/gui/importer/EntryFromFileCreatorManager.java @@ -36,14 +36,14 @@ public final class EntryFromFileCreatorManager { private final List entryCreators; - public EntryFromFileCreatorManager() { + public EntryFromFileCreatorManager(ExternalFileTypes externalFilesTypes) { entryCreators = new ArrayList<>(10); - entryCreators.add(new EntryFromPDFCreator()); + entryCreators.add(new EntryFromPDFCreator(externalFilesTypes)); // add a creator for each ExternalFileType if there is no specialized // creator existing. - Collection fileTypes = ExternalFileTypes.getInstance().getExternalFileTypeSelection(); + Collection fileTypes = externalFilesTypes.getExternalFileTypeSelection(); for (ExternalFileType exFileType : fileTypes) { if (!hasSpecialisedCreatorForExternalFileType(exFileType)) { diff --git a/src/main/java/org/jabref/gui/importer/EntryFromPDFCreator.java b/src/main/java/org/jabref/gui/importer/EntryFromPDFCreator.java index 11538571332..e4f288970e2 100644 --- a/src/main/java/org/jabref/gui/importer/EntryFromPDFCreator.java +++ b/src/main/java/org/jabref/gui/importer/EntryFromPDFCreator.java @@ -33,12 +33,12 @@ */ public class EntryFromPDFCreator extends EntryFromFileCreator { - public EntryFromPDFCreator() { - super(EntryFromPDFCreator.getPDFExternalFileType()); + public EntryFromPDFCreator(ExternalFileTypes externalFileTypes) { + super(EntryFromPDFCreator.getPDFExternalFileType(externalFileTypes)); } - private static ExternalFileType getPDFExternalFileType() { - Optional pdfFileType = ExternalFileTypes.getInstance().getExternalFileTypeByExt("pdf"); + private static ExternalFileType getPDFExternalFileType(ExternalFileTypes externalFileTypes) { + Optional pdfFileType = externalFileTypes.getExternalFileTypeByExt("pdf"); if (!pdfFileType.isPresent()) { return new ExternalFileType("PDF", "pdf", "application/pdf", "evince", "pdfSmall", IconTheme.JabRefIcon.PDF_FILE.getSmallIcon()); } @@ -90,7 +90,7 @@ private void addEntryDataFromPDDocumentInformation(File pdfFile, BibEntry entry) if (pdfDocInfo != null) { Optional entryDI = XMPUtil .getBibtexEntryFromDocumentInformation(document - .getDocumentInformation()); + .getDocumentInformation()); if (entryDI.isPresent()) { addEntryDataToEntry(entry, entryDI.get()); Calendar creationDate = pdfDocInfo.getCreationDate(); diff --git a/src/test/java/org/jabref/gui/importer/EntryFromFileCreatorManagerTest.java b/src/test/java/org/jabref/gui/importer/EntryFromFileCreatorManagerTest.java index 1d468030d97..f7c5edc838a 100644 --- a/src/test/java/org/jabref/gui/importer/EntryFromFileCreatorManagerTest.java +++ b/src/test/java/org/jabref/gui/importer/EntryFromFileCreatorManagerTest.java @@ -7,7 +7,9 @@ import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; +import java.util.Optional; +import org.jabref.gui.externalfiletype.ExternalFileTypes; import org.jabref.logic.importer.ImportDataTest; import org.jabref.logic.importer.ImportFormatPreferences; import org.jabref.logic.importer.ParserResult; @@ -17,8 +19,9 @@ import org.jabref.model.util.DummyFileUpdateMonitor; import org.jabref.testutils.category.GUITest; -import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.mockito.Answers; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -26,13 +29,24 @@ import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; @GUITest public class EntryFromFileCreatorManagerTest { + ImportFormatPreferences prefs = mock(ImportFormatPreferences.class, Answers.RETURNS_DEEP_STUBS); + ExternalFileTypes externalFileTypes; + + @BeforeEach + public void setUp() { + externalFileTypes = mock(ExternalFileTypes.class, Answers.RETURNS_DEEP_STUBS); + when(externalFileTypes.getExternalFileTypeByExt("pdf")).thenReturn(Optional.empty()); + + } + @Test public void testGetCreator() { - EntryFromFileCreatorManager manager = new EntryFromFileCreatorManager(); + EntryFromFileCreatorManager manager = new EntryFromFileCreatorManager(externalFileTypes); EntryFromFileCreator creator = manager.getEntryCreator(ImportDataTest.NOT_EXISTING_PDF); assertNull(creator); @@ -42,11 +56,10 @@ public void testGetCreator() { } @Test - @Disabled public void testAddEntrysFromFiles() throws IOException { try (FileInputStream stream = new FileInputStream(ImportDataTest.UNLINKED_FILES_TEST_BIB); InputStreamReader reader = new InputStreamReader(stream, StandardCharsets.UTF_8)) { - ParserResult result = new BibtexParser(mock(ImportFormatPreferences.class), new DummyFileUpdateMonitor()).parse(reader); + ParserResult result = new BibtexParser(prefs, new DummyFileUpdateMonitor()).parse(reader); BibDatabase database = result.getDatabase(); List files = new ArrayList<>(); @@ -54,7 +67,7 @@ public void testAddEntrysFromFiles() throws IOException { files.add(ImportDataTest.FILE_NOT_IN_DATABASE); files.add(ImportDataTest.NOT_EXISTING_PDF); - EntryFromFileCreatorManager manager = new EntryFromFileCreatorManager(); + EntryFromFileCreatorManager manager = new EntryFromFileCreatorManager(externalFileTypes); List errors = manager.addEntrysFromFiles(files, database, null, true); /** diff --git a/src/test/java/org/jabref/gui/importer/EntryFromPDFCreatorTest.java b/src/test/java/org/jabref/gui/importer/EntryFromPDFCreatorTest.java index b2f830ae0d1..380bfc6444c 100644 --- a/src/test/java/org/jabref/gui/importer/EntryFromPDFCreatorTest.java +++ b/src/test/java/org/jabref/gui/importer/EntryFromPDFCreatorTest.java @@ -5,6 +5,7 @@ import org.jabref.JabRefGUI; import org.jabref.gui.JabRefFrame; +import org.jabref.gui.externalfiletype.ExternalFileTypes; import org.jabref.logic.importer.ImportDataTest; import org.jabref.model.entry.BibEntry; import org.jabref.testutils.category.GUITest; @@ -12,6 +13,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; +import org.mockito.Answers; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -23,10 +25,12 @@ public class EntryFromPDFCreatorTest { private EntryFromPDFCreator entryCreator; + @BeforeEach public void setUp() { // Needed to initialize ExternalFileTypes - entryCreator = new EntryFromPDFCreator(); + entryCreator = new EntryFromPDFCreator(mock(ExternalFileTypes.class, Answers.RETURNS_DEEP_STUBS)); + // Needed for PdfImporter - still not enough JabRefGUI.setMainFrame(mock(JabRefFrame.class)); } diff --git a/src/test/java/org/jabref/model/entry/identifier/EprintTest.java b/src/test/java/org/jabref/model/entry/identifier/EprintTest.java index 651f05a7566..788767383ae 100644 --- a/src/test/java/org/jabref/model/entry/identifier/EprintTest.java +++ b/src/test/java/org/jabref/model/entry/identifier/EprintTest.java @@ -28,10 +28,12 @@ public void ignoreLeadingAndTrailingWhitespaces() { assertEquals("0706.0001v1", new Eprint(" 0706.0001v1 ").getEprint()); } + @Test public void rejectEmbeddedEprint() { assertThrows(IllegalArgumentException.class, () -> new Eprint("other stuff 0706.0001v1 end")); } + @Test public void rejectInvalidEprint() { assertThrows(IllegalArgumentException.class, () -> new Eprint("https://thisisnouri")); } From e7f245a11f95078596a5fb6884337c6ef7807429 Mon Sep 17 00:00:00 2001 From: Siedlerchr Date: Fri, 9 Feb 2018 17:51:22 +0100 Subject: [PATCH 18/94] Fix external File type visiblilty Convert FormatterTest to junit5 --- .../EntryFromFileCreatorManagerTest.java | 4 +- .../gui/importer/EntryFromPDFCreatorTest.java | 1 - .../jabref/logic/formatter/FormatterTest.java | 134 +++++++++--------- .../bibtexfields/RegexFormatterTest.java | 2 +- 4 files changed, 72 insertions(+), 69 deletions(-) diff --git a/src/test/java/org/jabref/gui/importer/EntryFromFileCreatorManagerTest.java b/src/test/java/org/jabref/gui/importer/EntryFromFileCreatorManagerTest.java index f7c5edc838a..38301e769ef 100644 --- a/src/test/java/org/jabref/gui/importer/EntryFromFileCreatorManagerTest.java +++ b/src/test/java/org/jabref/gui/importer/EntryFromFileCreatorManagerTest.java @@ -34,8 +34,8 @@ @GUITest public class EntryFromFileCreatorManagerTest { - ImportFormatPreferences prefs = mock(ImportFormatPreferences.class, Answers.RETURNS_DEEP_STUBS); - ExternalFileTypes externalFileTypes; + private final ImportFormatPreferences prefs = mock(ImportFormatPreferences.class, Answers.RETURNS_DEEP_STUBS); + private ExternalFileTypes externalFileTypes; @BeforeEach public void setUp() { diff --git a/src/test/java/org/jabref/gui/importer/EntryFromPDFCreatorTest.java b/src/test/java/org/jabref/gui/importer/EntryFromPDFCreatorTest.java index 380bfc6444c..17817eeb6b4 100644 --- a/src/test/java/org/jabref/gui/importer/EntryFromPDFCreatorTest.java +++ b/src/test/java/org/jabref/gui/importer/EntryFromPDFCreatorTest.java @@ -25,7 +25,6 @@ public class EntryFromPDFCreatorTest { private EntryFromPDFCreator entryCreator; - @BeforeEach public void setUp() { // Needed to initialize ExternalFileTypes diff --git a/src/test/java/org/jabref/logic/formatter/FormatterTest.java b/src/test/java/org/jabref/logic/formatter/FormatterTest.java index 1fdc8231a35..ab811a2ecdb 100644 --- a/src/test/java/org/jabref/logic/formatter/FormatterTest.java +++ b/src/test/java/org/jabref/logic/formatter/FormatterTest.java @@ -1,8 +1,7 @@ package org.jabref.logic.formatter; -import java.util.Arrays; -import java.util.Collection; import java.util.Collections; +import java.util.stream.Stream; import org.jabref.logic.formatter.bibtexfields.ClearFormatter; import org.jabref.logic.formatter.bibtexfields.HtmlToLatexFormatter; @@ -29,109 +28,114 @@ import org.jabref.logic.protectedterms.ProtectedTermsPreferences; import org.jabref.model.cleanup.Formatter; -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; -@RunWith(Parameterized.class) public class FormatterTest { - public Formatter formatter; - public FormatterTest(Formatter formatter) { - this.formatter = formatter; - } + private static ProtectedTermsLoader protectedTermsLoader; - @BeforeClass + @BeforeAll public static void setUp() { - ProtectTermsFormatter - .setProtectedTermsLoader( - new ProtectedTermsLoader(new ProtectedTermsPreferences(ProtectedTermsLoader.getInternalLists(), - Collections.emptyList(), Collections.emptyList(), Collections.emptyList()))); + protectedTermsLoader = new ProtectedTermsLoader( + new ProtectedTermsPreferences(ProtectedTermsLoader.getInternalLists(), Collections.emptyList(), + Collections.emptyList(), Collections.emptyList())); + + } - @Test - public void getNameReturnsNotNull() { + @ParameterizedTest + @MethodSource("getFormatters") + public void getNameReturnsNotNull(Formatter formatter) { assertNotNull(formatter.getName()); } - @Test - public void getNameReturnsNotEmpty() { + @ParameterizedTest + @MethodSource("getFormatters") + public void getNameReturnsNotEmpty(Formatter formatter) { assertNotEquals("", formatter.getName()); } - @Test - public void getKeyReturnsNotNull() { + @ParameterizedTest + @MethodSource("getFormatters") + public void getKeyReturnsNotNull(Formatter formatter) { assertNotNull(formatter.getKey()); } - @Test - public void getKeyReturnsNotEmpty() { + @ParameterizedTest + @MethodSource("getFormatters") + public void getKeyReturnsNotEmpty(Formatter formatter) { assertNotEquals("", formatter.getKey()); } - @Test(expected = NullPointerException.class) - public void formatOfNullThrowsException() { - formatter.format(null); + @ParameterizedTest + @MethodSource("getFormatters") + public void formatOfNullThrowsException(Formatter formatter) { + assertThrows(NullPointerException.class, () -> formatter.format(null)); } - @Test - public void formatOfEmptyStringReturnsEmpty() { + @ParameterizedTest + @MethodSource("getFormatters") + public void formatOfEmptyStringReturnsEmpty(Formatter formatter) { assertEquals("", formatter.format("")); } - @Test - public void formatNotReturnsNull() { + @ParameterizedTest + @MethodSource("getFormatters") + public void formatNotReturnsNull(Formatter formatter) { assertNotNull(formatter.format("string")); } - @Test - public void getDescriptionAlwaysNonEmpty() { + @ParameterizedTest + @MethodSource("getFormatters") + public void getDescriptionAlwaysNonEmpty(Formatter formatter) { assertFalse(formatter.getDescription().isEmpty()); } - @Test - public void getExampleInputAlwaysNonEmpty() { + @ParameterizedTest + @MethodSource("getFormatters") + public void getExampleInputAlwaysNonEmpty(Formatter formatter) { assertFalse(formatter.getExampleInput().isEmpty()); } - @Parameterized.Parameters(name = "{index}: {0}") - public static Collection instancesToTest() { + public static Stream getFormatters() { // all classes implementing {@link net.sf.jabref.model.cleanup.Formatter} // sorted alphabetically // Alternative: Use reflection - https://github.com/ronmamo/reflections // @formatter:off - return Arrays.asList( - new Object[]{new CapitalizeFormatter()}, - new Object[]{new ClearFormatter()}, - new Object[]{new HtmlToLatexFormatter()}, - new Object[]{new HtmlToUnicodeFormatter()}, - new Object[]{new IdentityFormatter()}, - new Object[]{new LatexCleanupFormatter()}, - new Object[]{new LatexToUnicodeFormatter()}, - new Object[]{new LowerCaseFormatter()}, - new Object[]{new MinifyNameListFormatter()}, - new Object[]{new NormalizeDateFormatter()}, - new Object[]{new NormalizeMonthFormatter()}, - new Object[]{new NormalizeNamesFormatter()}, - new Object[]{new NormalizePagesFormatter()}, - new Object[]{new OrdinalsToSuperscriptFormatter()}, - new Object[]{new ProtectTermsFormatter()}, - new Object[]{new RegexFormatter()}, - new Object[]{new RemoveBracesFormatter()}, - new Object[]{new SentenceCaseFormatter()}, - new Object[]{new TitleCaseFormatter()}, - new Object[]{new UnicodeToLatexFormatter()}, - new Object[]{new UnitsToLatexFormatter()}, - new Object[]{new UpperCaseFormatter()} - ); + return Stream.of( + new CapitalizeFormatter(), + new ClearFormatter(), + new HtmlToLatexFormatter(), + new HtmlToUnicodeFormatter(), + new IdentityFormatter(), + new LatexCleanupFormatter(), + new LatexToUnicodeFormatter(), + new LowerCaseFormatter(), + new MinifyNameListFormatter(), + new NormalizeDateFormatter(), + new NormalizeMonthFormatter(), + new NormalizeNamesFormatter(), + new NormalizePagesFormatter(), + new OrdinalsToSuperscriptFormatter(), + new ProtectTermsFormatter(protectedTermsLoader), + new RegexFormatter(), + new RemoveBracesFormatter(), + new SentenceCaseFormatter(), + new TitleCaseFormatter(), + new UnicodeToLatexFormatter(), + new UnitsToLatexFormatter(), + new UpperCaseFormatter()); + // @formatter:on } } diff --git a/src/test/java/org/jabref/logic/formatter/bibtexfields/RegexFormatterTest.java b/src/test/java/org/jabref/logic/formatter/bibtexfields/RegexFormatterTest.java index 4ce79fa5d4e..a01e31f1bdc 100644 --- a/src/test/java/org/jabref/logic/formatter/bibtexfields/RegexFormatterTest.java +++ b/src/test/java/org/jabref/logic/formatter/bibtexfields/RegexFormatterTest.java @@ -55,7 +55,6 @@ public void escapedBracesAreNotReplacedInTwoCases() { @Test public void escapedBracesAreNotReplacedAndProtectionStillWorks() { String regexInput = "(\" \",\"-\")"; - formatter.setRegex(regexInput); assertEquals("replace-spaces-{not these ones},-these-ones,-and-\\{-these-ones\\}", formatter.format("replace spaces {not these ones}, these ones, and \\{ these ones\\}")); } @@ -64,4 +63,5 @@ public void formatExample() { assertEquals("Please-replace-the-spaces", formatter.format(formatter.getExampleInput())); } + } From 276f5497df8a08d78de99ab04537b3f9c9119d3e Mon Sep 17 00:00:00 2001 From: Siedlerchr Date: Fri, 9 Feb 2018 18:28:27 +0100 Subject: [PATCH 19/94] fix some more tests convert architecture test to junit5 --- .../architecture/MainArchitectureTests.java | 69 +++++++++---------- .../org/jabref/gui/ClipBoardManagerTest.java | 6 +- .../gui/UpdateTimestampListenerTest.java | 31 +++------ .../DefaultAutoCompleterTest.java | 1 + .../logic/bibtex/BibEntryWriterTest.java | 3 +- .../fileformat/BibTeXMLImporterTestFiles.java | 2 + .../logic/net/MimeTypeDetectorTest.java | 4 +- .../logic/shared/DBMSProcessorTest.java | 3 +- .../logic/util/DevelopmentStageTest.java | 4 +- .../java/org/jabref/model/TreeNodeTest.java | 1 + .../org/jabref/model/entry/FieldNameTest.java | 2 +- 11 files changed, 58 insertions(+), 68 deletions(-) diff --git a/src/test/java/org/jabref/architecture/MainArchitectureTests.java b/src/test/java/org/jabref/architecture/MainArchitectureTests.java index 50b29c1ea69..6b6c95ab462 100644 --- a/src/test/java/org/jabref/architecture/MainArchitectureTests.java +++ b/src/test/java/org/jabref/architecture/MainArchitectureTests.java @@ -6,7 +6,6 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -16,11 +15,11 @@ import java.util.stream.Stream; import org.junit.Assert; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; -@RunWith(Parameterized.class) public class MainArchitectureTests { public static final String CLASS_ORG_JABREF_GLOBALS = "org.jabref.Globals"; @@ -35,17 +34,13 @@ public class MainArchitectureTests { private static final String EXCEPTION_PACKAGE_JAVA_FX_BEANS = "javafx.beans"; private static final String EXCEPTION_CLASS_JAVA_FX_COLOR = "javafx.scene.paint.Color"; - private final String firstPackage; - private final String secondPackage; - private final Map> exceptions; - - public MainArchitectureTests(String firstPackage, String secondPackage) { - this.firstPackage = firstPackage; - this.secondPackage = secondPackage; + private static Map> exceptions; + @BeforeAll + public static void setUp() { + exceptions = new HashMap<>(); // Add exceptions for the architectural test here // Note that bending the architectural constraints should not be done inconsiderately - exceptions = new HashMap<>(); List logicExceptions = new ArrayList<>(4); logicExceptions.add(EXCEPTION_PACKAGE_JAVA_AWT_GEOM); @@ -63,32 +58,29 @@ public MainArchitectureTests(String firstPackage, String secondPackage) { exceptions.put(PACKAGE_ORG_JABREF_MODEL, modelExceptions); } - - @Parameterized.Parameters(name = "{index} -- is {0} independent of {1}?") - public static Iterable data() { - return Arrays.asList( - new Object[][]{ - {PACKAGE_ORG_JABREF_LOGIC, PACKAGE_JAVA_AWT}, - {PACKAGE_ORG_JABREF_LOGIC, PACKAGE_JAVAX_SWING}, - {PACKAGE_ORG_JABREF_LOGIC, PACKAGE_JAVA_FX}, - {PACKAGE_ORG_JABREF_LOGIC, PACKAGE_ORG_JABREF_GUI}, - {PACKAGE_ORG_JABREF_LOGIC, CLASS_ORG_JABREF_GLOBALS}, - - {PACKAGE_ORG_JABREF_MODEL, PACKAGE_JAVA_AWT}, - {PACKAGE_ORG_JABREF_MODEL, PACKAGE_JAVAX_SWING}, - {PACKAGE_ORG_JABREF_MODEL, PACKAGE_JAVA_FX}, - {PACKAGE_ORG_JABREF_MODEL, PACKAGE_ORG_JABREF_GUI}, - {PACKAGE_ORG_JABREF_MODEL, PACKAGE_ORG_JABREF_LOGIC}, - {PACKAGE_ORG_JABREF_MODEL, CLASS_ORG_JABREF_GLOBALS} - } - ); + public static Stream getPackages() { + + return Stream.of( + Arguments.of(PACKAGE_ORG_JABREF_LOGIC, PACKAGE_JAVA_AWT), + Arguments.of(PACKAGE_ORG_JABREF_LOGIC, PACKAGE_JAVAX_SWING), + Arguments.of(PACKAGE_ORG_JABREF_LOGIC, PACKAGE_JAVA_FX), + Arguments.of(PACKAGE_ORG_JABREF_LOGIC, PACKAGE_ORG_JABREF_GUI), + Arguments.of(PACKAGE_ORG_JABREF_LOGIC, CLASS_ORG_JABREF_GLOBALS), + + Arguments.of(PACKAGE_ORG_JABREF_MODEL, PACKAGE_JAVA_AWT), + Arguments.of(PACKAGE_ORG_JABREF_MODEL, PACKAGE_JAVAX_SWING), + Arguments.of(PACKAGE_ORG_JABREF_MODEL, PACKAGE_JAVA_FX), + Arguments.of(PACKAGE_ORG_JABREF_MODEL, PACKAGE_ORG_JABREF_GUI), + Arguments.of(PACKAGE_ORG_JABREF_MODEL, PACKAGE_ORG_JABREF_LOGIC), + Arguments.of(PACKAGE_ORG_JABREF_MODEL, CLASS_ORG_JABREF_GLOBALS)); } - @Test - public void firstPackageIsIndependentOfSecondPackage() throws IOException { - Predicate isExceptionPackage = (s) -> - s.startsWith("import " + secondPackage) - && exceptions.getOrDefault(firstPackage, Collections.emptyList()).stream() + @ParameterizedTest(name = "{index} -- is {0} independent of {1}?") + @MethodSource("getPackages") + public void firstPackageIsIndependentOfSecondPackage(String firstPackage, String secondPackage) throws IOException { + Predicate isExceptionPackage = (s) -> s.startsWith("import " + secondPackage) + && exceptions.getOrDefault(firstPackage, Collections.emptyList()) + .stream() .noneMatch(exception -> s.startsWith("import " + exception)); Predicate isPackage = (s) -> s.startsWith("package " + firstPackage); @@ -109,7 +101,8 @@ public void firstPackageIsIndependentOfSecondPackage() throws IOException { } catch (IOException e) { return false; } - }).collect(Collectors.toList()); + }) + .collect(Collectors.toList()); Assert.assertEquals("The following classes are not allowed to depend on " + secondPackage, Collections.emptyList(), files); diff --git a/src/test/java/org/jabref/gui/ClipBoardManagerTest.java b/src/test/java/org/jabref/gui/ClipBoardManagerTest.java index b0b5e2dcf76..6c0c9347e04 100644 --- a/src/test/java/org/jabref/gui/ClipBoardManagerTest.java +++ b/src/test/java/org/jabref/gui/ClipBoardManagerTest.java @@ -12,8 +12,8 @@ import org.jabref.logic.importer.ParserResult; import org.jabref.model.entry.BibEntry; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.mockito.ArgumentMatchers; import static org.junit.Assert.*; @@ -26,7 +26,7 @@ public class ClipBoardManagerTest { private Transferable content; private ImportFormatReader importFormatReader; - @Before + @BeforeEach public void setUp() throws Exception { importFormatReader = mock(ImportFormatReader.class); diff --git a/src/test/java/org/jabref/gui/UpdateTimestampListenerTest.java b/src/test/java/org/jabref/gui/UpdateTimestampListenerTest.java index 6a27c3949b5..664b78590bd 100644 --- a/src/test/java/org/jabref/gui/UpdateTimestampListenerTest.java +++ b/src/test/java/org/jabref/gui/UpdateTimestampListenerTest.java @@ -7,28 +7,23 @@ import org.jabref.model.entry.BibEntry; import org.jabref.preferences.JabRefPreferences; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; public class UpdateTimestampListenerTest { - @Rule - public ExpectedException thrown = ExpectedException.none(); - private BibDatabase database; private BibEntry bibEntry; private JabRefPreferences preferencesMock; private TimestampPreferences timestampPreferencesMock; - @Before - public void setUp(){ + @BeforeEach + public void setUp() { database = new BibDatabase(); bibEntry = new BibEntry(); @@ -41,7 +36,7 @@ public void setUp(){ } @Test - public void updateTimestampEnabled(){ + public void updateTimestampEnabled() { final String timestampField = "timestamp"; final String baseDate = "2000-1-1"; final String newDate = "2000-1-2"; @@ -54,19 +49,17 @@ public void updateTimestampEnabled(){ bibEntry.setField(timestampField, baseDate); - assertEquals("Initial timestamp not set correctly", - Optional.of(baseDate), bibEntry.getField(timestampField)); + assertEquals(Optional.of(baseDate), bibEntry.getField(timestampField), "Initial timestamp not set correctly"); database.registerListener(new UpdateTimestampListener(preferencesMock)); bibEntry.setField("test", "some value"); - assertEquals("Timestamp not set correctly after entry changed", - Optional.of(newDate), bibEntry.getField(timestampField)); + assertEquals(Optional.of(newDate), bibEntry.getField(timestampField), "Timestamp not set correctly after entry changed"); } @Test - public void updateTimestampDisabled(){ + public void updateTimestampDisabled() { final String timestampField = "timestamp"; final String baseDate = "2000-1-1"; final String newDate = "2000-1-2"; @@ -79,14 +72,12 @@ public void updateTimestampDisabled(){ bibEntry.setField(timestampField, baseDate); - assertEquals("Initial timestamp not set correctly", - Optional.of(baseDate), bibEntry.getField(timestampField)); + assertEquals(Optional.of(baseDate), bibEntry.getField(timestampField), "Initial timestamp not set correctly"); database.registerListener(new UpdateTimestampListener(preferencesMock)); bibEntry.setField("test", "some value"); - assertEquals("New timestamp set after entry changed even though updates were disabled", - Optional.of(baseDate), bibEntry.getField(timestampField)); + assertEquals(Optional.of(baseDate), bibEntry.getField(timestampField), "New timestamp set after entry changed even though updates were disabled"); } } diff --git a/src/test/java/org/jabref/gui/autocompleter/DefaultAutoCompleterTest.java b/src/test/java/org/jabref/gui/autocompleter/DefaultAutoCompleterTest.java index 0a9cba14823..41719918129 100644 --- a/src/test/java/org/jabref/gui/autocompleter/DefaultAutoCompleterTest.java +++ b/src/test/java/org/jabref/gui/autocompleter/DefaultAutoCompleterTest.java @@ -17,6 +17,7 @@ public class DefaultAutoCompleterTest { private WordSuggestionProvider autoCompleter; + @Test public void initAutoCompleterWithNullFieldThrowsException() { assertThrows(NullPointerException.class, () -> new WordSuggestionProvider(null)); } diff --git a/src/test/java/org/jabref/logic/bibtex/BibEntryWriterTest.java b/src/test/java/org/jabref/logic/bibtex/BibEntryWriterTest.java index 7ab162ba874..71aeae47d96 100644 --- a/src/test/java/org/jabref/logic/bibtex/BibEntryWriterTest.java +++ b/src/test/java/org/jabref/logic/bibtex/BibEntryWriterTest.java @@ -419,7 +419,8 @@ public void trimFieldContents() throws IOException { assertEquals(expected, actual); } - public void writeThrowsErrorIfFieldContainsUnbalancedBraces() throws IOException { + @Test + public void writeThrowsErrorIfFieldContainsUnbalancedBraces() { StringWriter stringWriter = new StringWriter(); BibEntry entry = new BibEntry("article"); diff --git a/src/test/java/org/jabref/logic/importer/fileformat/BibTeXMLImporterTestFiles.java b/src/test/java/org/jabref/logic/importer/fileformat/BibTeXMLImporterTestFiles.java index 163cd6cb6b0..0e7fc1627c1 100644 --- a/src/test/java/org/jabref/logic/importer/fileformat/BibTeXMLImporterTestFiles.java +++ b/src/test/java/org/jabref/logic/importer/fileformat/BibTeXMLImporterTestFiles.java @@ -11,12 +11,14 @@ public class BibTeXMLImporterTestFiles { private static final String FILE_ENDING = ".xml"; + @SuppressWarnings("unused") private static Stream fileNames() throws IOException { Predicate fileName = name -> name.startsWith("BibTeXMLImporterTest") && name.endsWith(FILE_ENDING); return ImporterTestEngine.getTestFiles(fileName).stream(); } + @SuppressWarnings("unused") private static Stream nonBibTeXMLfileNames() throws IOException { Predicate fileName = name -> !name.startsWith("BibTeXMLImporterTest"); return ImporterTestEngine.getTestFiles(fileName).stream(); diff --git a/src/test/java/org/jabref/logic/net/MimeTypeDetectorTest.java b/src/test/java/org/jabref/logic/net/MimeTypeDetectorTest.java index ce6efd9f64b..225808a91ee 100644 --- a/src/test/java/org/jabref/logic/net/MimeTypeDetectorTest.java +++ b/src/test/java/org/jabref/logic/net/MimeTypeDetectorTest.java @@ -17,8 +17,8 @@ import static org.junit.Assert.assertTrue; public class MimeTypeDetectorTest { - @Rule - public WireMockRule wireMockRule = new WireMockRule(); + + @Rule public WireMockRule wireMockRule = new WireMockRule(); @Test public void handlePermanentRedirections() throws IOException { diff --git a/src/test/java/org/jabref/logic/shared/DBMSProcessorTest.java b/src/test/java/org/jabref/logic/shared/DBMSProcessorTest.java index 6aa6e2ec8e2..1bf4e3e3249 100644 --- a/src/test/java/org/jabref/logic/shared/DBMSProcessorTest.java +++ b/src/test/java/org/jabref/logic/shared/DBMSProcessorTest.java @@ -33,8 +33,7 @@ public class DBMSProcessorTest { private DBMSConnection dbmsConnection; private DBMSProcessor dbmsProcessor; - @Parameter - public DBMSType dbmsType; + @Parameter public DBMSType dbmsType; @BeforeEach public void setUp() throws SQLException, InvalidDBMSConnectionPropertiesException { diff --git a/src/test/java/org/jabref/logic/util/DevelopmentStageTest.java b/src/test/java/org/jabref/logic/util/DevelopmentStageTest.java index f3c482fb309..5e520890608 100644 --- a/src/test/java/org/jabref/logic/util/DevelopmentStageTest.java +++ b/src/test/java/org/jabref/logic/util/DevelopmentStageTest.java @@ -1,6 +1,8 @@ package org.jabref.logic.util; -import org.junit.Test; + + +import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; diff --git a/src/test/java/org/jabref/model/TreeNodeTest.java b/src/test/java/org/jabref/model/TreeNodeTest.java index 1c4d2b989b9..577c2420d8d 100644 --- a/src/test/java/org/jabref/model/TreeNodeTest.java +++ b/src/test/java/org/jabref/model/TreeNodeTest.java @@ -26,6 +26,7 @@ public void setUp() { subscriber = mock(Consumer.class); } + @Test public void constructorChecksThatClassImplementsCorrectInterface() { assertThrows(UnsupportedOperationException.class, () -> new WrongTreeNodeImplementation()); diff --git a/src/test/java/org/jabref/model/entry/FieldNameTest.java b/src/test/java/org/jabref/model/entry/FieldNameTest.java index b390886e1f5..ae0eb69c2d2 100644 --- a/src/test/java/org/jabref/model/entry/FieldNameTest.java +++ b/src/test/java/org/jabref/model/entry/FieldNameTest.java @@ -1,6 +1,6 @@ package org.jabref.model.entry; -import org.junit.Test; +import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; From f1977f53e39b578e1cc4015f7b5970b6d66b6c16 Mon Sep 17 00:00:00 2001 From: cerrisantos Date: Sun, 11 Feb 2018 16:06:21 +0000 Subject: [PATCH 20/94] Default ID type in the ID-based entry generator (#3712) * Added preference for ID fetcher * Fixed code style issues * Fixed code style issue --- CHANGELOG.md | 1 + src/main/java/org/jabref/gui/EntryTypeDialog.java | 8 +++++--- .../java/org/jabref/preferences/JabRefPreferences.java | 8 ++++++++ 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0296228eb52..edb325d075c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ We refer to [GitHub issues](https://github.com/JabRef/jabref/issues) by using `# ## [Unreleased] ### Changed +- Changed ID-based entry generator to store the last used fetcher. [#2796] (https://github.com/JabRef/jabref/issues/2796) - Reorganised annotation information on the right side of the "File annotations" tab. [#3109](https://github.com/JabRef/jabref/issues/3109) - We now show a small notification icon in the entry editor when we detect data inconsistency or other problems. [#3145](https://github.com/JabRef/jabref/issues/3145) - We added [oaDOI](https://oadoi.org/) as a fulltext provider, so that JabRef is now able to provide fulltexts for more than 90 million open-access articles. diff --git a/src/main/java/org/jabref/gui/EntryTypeDialog.java b/src/main/java/org/jabref/gui/EntryTypeDialog.java index 30669a5306e..84e2a78d4d1 100644 --- a/src/main/java/org/jabref/gui/EntryTypeDialog.java +++ b/src/main/java/org/jabref/gui/EntryTypeDialog.java @@ -34,7 +34,6 @@ import org.jabref.logic.importer.FetcherException; import org.jabref.logic.importer.IdBasedFetcher; import org.jabref.logic.importer.WebFetchers; -import org.jabref.logic.importer.fetcher.DoiFetcher; import org.jabref.logic.l10n.Localization; import org.jabref.model.EntryTypes; import org.jabref.model.database.BibDatabaseMode; @@ -43,6 +42,7 @@ import org.jabref.model.entry.BibtexEntryTypes; import org.jabref.model.entry.EntryType; import org.jabref.model.entry.IEEETranEntryTypes; +import org.jabref.preferences.JabRefPreferences; import com.jgoodies.forms.builder.ButtonBarBuilder; import org.slf4j.Logger; @@ -166,8 +166,8 @@ private JPanel createIdFetcherPanel() { comboBox = new JComboBox<>(); WebFetchers.getIdBasedFetchers(Globals.prefs.getImportFormatPreferences()).forEach(fetcher -> comboBox.addItem(fetcher.getName())); - // set DOI as default - comboBox.setSelectedItem(DoiFetcher.NAME); + + comboBox.setSelectedItem(Globals.prefs.get(JabRefPreferences.ID_ENTRY_GENERATOR)); generateButton.addActionListener(action -> { fetcherWorker.execute(); @@ -287,6 +287,8 @@ protected Optional doInBackground() throws Exception { generateButton.setEnabled(false); generateButton.setText(Localization.lang("Searching...")); }); + + Globals.prefs.put(JabRefPreferences.ID_ENTRY_GENERATOR,String.valueOf(comboBox.getSelectedItem())); searchID = idTextField.getText().trim(); searchID = searchID.replaceAll(" ", ""); fetcher = WebFetchers.getIdBasedFetchers(Globals.prefs.getImportFormatPreferences()).get(comboBox.getSelectedIndex()); diff --git a/src/main/java/org/jabref/preferences/JabRefPreferences.java b/src/main/java/org/jabref/preferences/JabRefPreferences.java index 11227390b10..149dec57782 100644 --- a/src/main/java/org/jabref/preferences/JabRefPreferences.java +++ b/src/main/java/org/jabref/preferences/JabRefPreferences.java @@ -50,6 +50,7 @@ import org.jabref.logic.cleanup.CleanupPreset; import org.jabref.logic.cleanup.Cleanups; import org.jabref.logic.importer.ImportFormatPreferences; +import org.jabref.logic.importer.fetcher.DoiFetcher; import org.jabref.logic.journals.JournalAbbreviationLoader; import org.jabref.logic.journals.JournalAbbreviationPreferences; import org.jabref.logic.l10n.Localization; @@ -374,6 +375,9 @@ public class JabRefPreferences implements PreferencesService { //AutcompleteFields - public because needed for pref migration public static final String AUTOCOMPLETER_COMPLETE_FIELDS = "autoCompleteFields"; + // Id Entry Generator Preferences + public static final String ID_ENTRY_GENERATOR = "idEntryGenerator"; + // Auto completion private static final String AUTO_COMPLETE = "autoComplete"; private static final String AUTOCOMPLETER_FIRSTNAME_MODE = "autoCompFirstNameMode"; @@ -462,6 +466,10 @@ private JabRefPreferences() { defaults.put(BIBLATEX_DEFAULT_MODE, Boolean.FALSE); + // Set DOI to be the default ID entry generator + defaults.put(ID_ENTRY_GENERATOR, DoiFetcher.NAME); + + if (OS.OS_X) { defaults.put(FONT_FAMILY, "SansSerif"); defaults.put(WIN_LOOK_AND_FEEL, UIManager.getSystemLookAndFeelClassName()); From 1dfc4e556d8d06e9da57d425f3c86980cb74354d Mon Sep 17 00:00:00 2001 From: Escoul Date: Tue, 13 Feb 2018 12:37:03 +0100 Subject: [PATCH 21/94] Changes regarding issue koppor#277: Fix the name of the group editing window to "Add group" instead of "Edit Group" when adding a new group. The group editing window can now also be called by double-clicking the group to be edited. --- CHANGELOG.md | 2 ++ src/main/java/org/jabref/gui/groups/GroupDialog.java | 3 ++- .../org/jabref/gui/groups/GroupTreeController.java | 12 ++++++++++++ src/main/resources/l10n/JabRef_en.properties | 1 + 4 files changed, 17 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index edb325d075c..cc90711b19e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ For more details refer to the [field mapping help page](http://help.jabref.org/e - We improved file saving so that hard links are now preserved when a save is performed [#2633](https://github.com/JabRef/jabref/issues/2633) - We changed the default dialog option when removing a [file link](http://help.jabref.org/en/FileLinks#adding-external-links-to-an-entry) from an entry. The new default removes the linked file from the entry instead of deleting the file from disk. [#3679](https://github.com/JabRef/jabref/issues/3679) +- The group editing window can now also be called by double-clicking the group to be edited. [koppor#277](https://github.com/koppor/jabref/issues/277) ### Fixed - We fixed an issue where pressing space caused the cursor to jump to the start of the text field. [#3471](https://github.com/JabRef/jabref/issues/3471) @@ -37,6 +38,7 @@ The new default removes the linked file from the entry instead of deleting the f - Chaining modifiers in BibTeX key pattern now works as described in the documentation. [#3648](https://github.com/JabRef/jabref/issues/3648) - We fixed an issue where not all bibtex/biblatex fields would be exported as latex-free to MS-Office XML [koppor#284](https://github.com/koppor/jabref/issues/284) - We fixed an issue where linked files would be deleted from bibliography entries despite choosing the "Cancel" option in the dialog menu. +- We fixed the name of the group editing window to "Add group" instead of "Edit Group" when adding a new group. [koppor#277](https://github.com/koppor/jabref/issues/277) ### Removed - We removed the [Look and Feels from JGoodies](http://www.jgoodies.com/freeware/libraries/looks/), because the open source version is not compatible with Java 9. diff --git a/src/main/java/org/jabref/gui/groups/GroupDialog.java b/src/main/java/org/jabref/gui/groups/GroupDialog.java index 7ac7dc0ceb8..e90be1b60fe 100644 --- a/src/main/java/org/jabref/gui/groups/GroupDialog.java +++ b/src/main/java/org/jabref/gui/groups/GroupDialog.java @@ -148,7 +148,8 @@ public Dimension getPreferredSize() { * created. */ public GroupDialog(JabRefFrame jabrefFrame, AbstractGroup editedGroup) { - super(jabrefFrame, Localization.lang("Edit group"), true, GroupDialog.class); + super(jabrefFrame, (editedGroup == null) ? Localization.lang("Add group") : Localization.lang("Edit group"), + true, GroupDialog.class); // set default values (overwritten if editedGroup != null) keywordGroupSearchField.setText(jabrefFrame.prefs().get(JabRefPreferences.GROUPS_DEFAULT_FIELD)); diff --git a/src/main/java/org/jabref/gui/groups/GroupTreeController.java b/src/main/java/org/jabref/gui/groups/GroupTreeController.java index 2948006d868..b440b163eb5 100644 --- a/src/main/java/org/jabref/gui/groups/GroupTreeController.java +++ b/src/main/java/org/jabref/gui/groups/GroupTreeController.java @@ -28,6 +28,7 @@ import javafx.scene.input.ClipboardContent; import javafx.scene.input.DragEvent; import javafx.scene.input.Dragboard; +import javafx.scene.input.MouseButton; import javafx.scene.input.TransferMode; import javafx.scene.layout.StackPane; import javafx.scene.text.Text; @@ -173,6 +174,17 @@ public void initialize() { row.setDisclosureNode(null); row.disclosureNodeProperty().addListener((observable, oldValue, newValue) -> row.setDisclosureNode(null)); + // Opens the group's edit window when the group gets double clicked + row.setOnMouseClicked((mouseClickedEvent) -> { + if (mouseClickedEvent.getButton().equals(MouseButton.PRIMARY) + && (mouseClickedEvent.getClickCount() == 2)) { + GroupNodeViewModel groupToEdit = EasyBind.monadic(row.itemProperty()).getValue(); + if (groupToEdit != null) { + viewModel.editGroup(groupToEdit); + } + } + }); + // Add context menu (only for non-null items) row.contextMenuProperty().bind( EasyBind.monadic(row.itemProperty()) diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties index 7fd958d6894..0ac3e123a66 100644 --- a/src/main/resources/l10n/JabRef_en.properties +++ b/src/main/resources/l10n/JabRef_en.properties @@ -386,6 +386,7 @@ Edit\ entry=Edit entry Save\ file=Save file Edit\ file\ type=Edit file type +Add\ group=Add group Edit\ group=Edit group From a5bede1f56f86dfc57e4ee0d9cd03b9c9b14d418 Mon Sep 17 00:00:00 2001 From: Joerg Lenhard Date: Tue, 13 Feb 2018 16:22:57 +0100 Subject: [PATCH 22/94] Migrate magnifier icon back to Swing --- src/main/java/org/jabref/gui/IconTheme.java | 2 +- .../org/jabref/gui/search/GlobalSearchBar.java | 10 +++++++++- .../org/jabref/gui/search/SearchTextField.java | 17 ----------------- 3 files changed, 10 insertions(+), 19 deletions(-) diff --git a/src/main/java/org/jabref/gui/IconTheme.java b/src/main/java/org/jabref/gui/IconTheme.java index ad99a9b6543..249e40ccc3f 100644 --- a/src/main/java/org/jabref/gui/IconTheme.java +++ b/src/main/java/org/jabref/gui/IconTheme.java @@ -198,7 +198,7 @@ public enum JabRefIcon { REFRESH(MaterialDesignIcon.REFRESH), DELETE_ENTRY(MaterialDesignIcon.DELETE), SEARCH(MaterialDesignIcon.MAGNIFY), - ADVANCED_SEARCH(Color.ORANGE, MaterialDesignIcon.MAGNIFY), + ADVANCED_SEARCH(Color.CYAN, MaterialDesignIcon.MAGNIFY), PREFERENCES(MaterialDesignIcon.SETTINGS), HELP(MaterialDesignIcon.HELP_CIRCLE), UP(MaterialDesignIcon.CHEVRON_UP), diff --git a/src/main/java/org/jabref/gui/search/GlobalSearchBar.java b/src/main/java/org/jabref/gui/search/GlobalSearchBar.java index a25a646ed57..fcec6fbc2fc 100644 --- a/src/main/java/org/jabref/gui/search/GlobalSearchBar.java +++ b/src/main/java/org/jabref/gui/search/GlobalSearchBar.java @@ -22,6 +22,7 @@ import javafx.css.PseudoClass; import javafx.embed.swing.JFXPanel; +import javafx.scene.Node; import javafx.scene.Scene; import javafx.scene.control.ContentDisplay; import javafx.scene.control.TextField; @@ -78,6 +79,8 @@ public class GlobalSearchBar extends JPanel { private SearchDisplayMode searchDisplayMode; + private JLabel searchIcon = new JLabel(IconTheme.JabRefIcon.SEARCH.getIcon()); + /** * if this flag is set the searchbar won't be selected after the next search */ @@ -195,6 +198,7 @@ public void actionPerformed(ActionEvent e) { setLayout(new FlowLayout(FlowLayout.RIGHT)); JToolBar toolBar = new OSXCompatibleToolbar(); toolBar.setFloatable(false); + toolBar.add(searchIcon); toolBar.add(container); toolBar.add(openCurrentResultsInDialog); toolBar.addSeparator(); @@ -391,7 +395,11 @@ public void updateResults(int matched, TextFlow description, boolean grammarBase currentResults.setText(Localization.lang("Found %0 results.", String.valueOf(matched))); searchField.pseudoClassStateChanged(CLASS_RESULTS_FOUND, true); } - SearchTextField.switchSearchColor(searchField, grammarBasedSearch); + if (grammarBasedSearch) { + searchIcon.setIcon(IconTheme.JabRefIcon.ADVANCED_SEARCH.getIcon()); + } else { + searchIcon.setIcon(IconTheme.JabRefIcon.SEARCH.getIcon()); + } Tooltip tooltip = new Tooltip(); tooltip.setContentDisplay(ContentDisplay.GRAPHIC_ONLY); tooltip.setGraphic(description); diff --git a/src/main/java/org/jabref/gui/search/SearchTextField.java b/src/main/java/org/jabref/gui/search/SearchTextField.java index e0f9f9f686a..334b5a751aa 100644 --- a/src/main/java/org/jabref/gui/search/SearchTextField.java +++ b/src/main/java/org/jabref/gui/search/SearchTextField.java @@ -1,10 +1,7 @@ package org.jabref.gui.search; -import javafx.scene.Node; import javafx.scene.control.TextField; -import org.jabref.gui.IconTheme; -import org.jabref.gui.util.DefaultTaskExecutor; import org.jabref.logic.l10n.Localization; import org.controlsfx.control.textfield.CustomTextField; @@ -15,21 +12,7 @@ public class SearchTextField { public static TextField create() { CustomTextField textField = (CustomTextField) TextFields.createClearableTextField(); textField.setPromptText(Localization.lang("Search") + "..."); - Node node = IconTheme.JabRefIcon.SEARCH.getGraphicNode(); - node.setStyle("-fx-text-fill: #00ffff"); - textField.setLeft(node); return textField; } - public static void switchSearchColor(TextField textField, boolean grammarBasedSearch) { - if (grammarBasedSearch) { - DefaultTaskExecutor.runInJavaFXThread(() -> - ((CustomTextField) textField).setLeft(IconTheme.JabRefIcon.ADVANCED_SEARCH.getGraphicNode())); - } else { - DefaultTaskExecutor.runInJavaFXThread(() -> - ((CustomTextField) textField).setLeft(IconTheme.JabRefIcon.SEARCH.getGraphicNode())); - } - } - - } From 89b3aa0d7fdbe16cd2e6e142baf42fbd6b85a420 Mon Sep 17 00:00:00 2001 From: Joerg Lenhard Date: Tue, 13 Feb 2018 16:26:57 +0100 Subject: [PATCH 23/94] Fix imports --- src/main/java/org/jabref/gui/search/GlobalSearchBar.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/org/jabref/gui/search/GlobalSearchBar.java b/src/main/java/org/jabref/gui/search/GlobalSearchBar.java index fcec6fbc2fc..7ffc8cc100e 100644 --- a/src/main/java/org/jabref/gui/search/GlobalSearchBar.java +++ b/src/main/java/org/jabref/gui/search/GlobalSearchBar.java @@ -22,7 +22,6 @@ import javafx.css.PseudoClass; import javafx.embed.swing.JFXPanel; -import javafx.scene.Node; import javafx.scene.Scene; import javafx.scene.control.ContentDisplay; import javafx.scene.control.TextField; From 3ae988517fda8a0397ee3c084713302144d7c8f5 Mon Sep 17 00:00:00 2001 From: Escoul Date: Tue, 13 Feb 2018 17:45:28 +0100 Subject: [PATCH 24/94] Remove unnecessary Easybind.monadic call. --- src/main/java/org/jabref/gui/groups/GroupTreeController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jabref/gui/groups/GroupTreeController.java b/src/main/java/org/jabref/gui/groups/GroupTreeController.java index b440b163eb5..e1420b0ebe2 100644 --- a/src/main/java/org/jabref/gui/groups/GroupTreeController.java +++ b/src/main/java/org/jabref/gui/groups/GroupTreeController.java @@ -178,7 +178,7 @@ public void initialize() { row.setOnMouseClicked((mouseClickedEvent) -> { if (mouseClickedEvent.getButton().equals(MouseButton.PRIMARY) && (mouseClickedEvent.getClickCount() == 2)) { - GroupNodeViewModel groupToEdit = EasyBind.monadic(row.itemProperty()).getValue(); + GroupNodeViewModel groupToEdit = row.itemProperty().getValue(); if (groupToEdit != null) { viewModel.editGroup(groupToEdit); } From 7bd2ca057d826aa007de54c2449dc3486ccd9fb9 Mon Sep 17 00:00:00 2001 From: Brainsucker92 Date: Wed, 14 Feb 2018 13:18:56 +0100 Subject: [PATCH 25/94] Code cleanup AbbreviateAction.java (#3717) * Removed unnecessary code. Increased performance slightly * Fixed formatting issued. * Code formatting --- .../jabref/gui/journals/AbbreviateAction.java | 22 +++++++------------ 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/src/main/java/org/jabref/gui/journals/AbbreviateAction.java b/src/main/java/org/jabref/gui/journals/AbbreviateAction.java index bdd39c5dac7..94798723075 100644 --- a/src/main/java/org/jabref/gui/journals/AbbreviateAction.java +++ b/src/main/java/org/jabref/gui/journals/AbbreviateAction.java @@ -1,6 +1,5 @@ package org.jabref.gui.journals; -import java.util.ArrayList; import java.util.List; import java.util.concurrent.Callable; @@ -14,7 +13,8 @@ import org.jabref.model.entry.InternalBibtexFields; /** - * Converts journal full names to either iso or medline abbreviations for all selected entries. + * Converts journal full names to either iso or medline abbreviations for all + * selected entries. */ public class AbbreviateAction extends AbstractWorker { @@ -22,7 +22,6 @@ public class AbbreviateAction extends AbstractWorker { private String message = ""; private final boolean iso; - public AbbreviateAction(BasePanel panel, boolean iso) { this.panel = panel; this.iso = iso; @@ -36,17 +35,14 @@ public void init() { @Override public void run() { List entries = panel.getSelectedEntries(); - if (entries == null) { - return; - } - UndoableAbbreviator undoableAbbreviator = new UndoableAbbreviator(Globals.journalAbbreviationLoader - .getRepository(Globals.prefs.getJournalAbbreviationPreferences()), iso); + UndoableAbbreviator undoableAbbreviator = new UndoableAbbreviator( + Globals.journalAbbreviationLoader.getRepository(Globals.prefs.getJournalAbbreviationPreferences()), + iso); NamedCompound ce = new NamedCompound(Localization.lang("Abbreviate journal names")); int count = 0; - List futures = new ArrayList<>(); for (BibEntry entry : entries) { Callable callable = () -> { for (String journalField : InternalBibtexFields.getJournalNameFields()) { @@ -57,13 +53,11 @@ public void run() { return false; }; - JabRefExecutorService.INSTANCE.executeAndWait(callable); - futures.add(JabRefExecutorService.INSTANCE.executeAndWait(callable)); - } - for (Boolean future : futures) { - if (future) + boolean result = JabRefExecutorService.INSTANCE.executeAndWait(callable); + if (result) { count++; + } } if (count > 0) { From 3e6a65df361ecd58d3e627bdfe63247958e8fafc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Lenhard?= Date: Wed, 14 Feb 2018 14:33:30 +0100 Subject: [PATCH 26/94] Add cleanup operation for replacing ligatures (#3718) --- CHANGELOG.md | 1 + .../org/jabref/logic/cleanup/Cleanups.java | 5 +- .../ReplaceUnicodeLigaturesFormatter.java | 53 +++++++++++++++ .../util/strings/UnicodeLigaturesMap.java | 68 +++++++++++++++++++ src/main/resources/l10n/JabRef_en.properties | 3 + .../ReplaceUnicodeLigaturesFormatterTest.java | 38 +++++++++++ 6 files changed, 166 insertions(+), 2 deletions(-) create mode 100644 src/main/java/org/jabref/logic/layout/format/ReplaceUnicodeLigaturesFormatter.java create mode 100644 src/main/java/org/jabref/logic/util/strings/UnicodeLigaturesMap.java create mode 100644 src/test/java/org/jabref/logic/layout/format/ReplaceUnicodeLigaturesFormatterTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index cc90711b19e..951f4220d01 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ For more details refer to the [field mapping help page](http://help.jabref.org/e - We changed the default dialog option when removing a [file link](http://help.jabref.org/en/FileLinks#adding-external-links-to-an-entry) from an entry. The new default removes the linked file from the entry instead of deleting the file from disk. [#3679](https://github.com/JabRef/jabref/issues/3679) - The group editing window can now also be called by double-clicking the group to be edited. [koppor#277](https://github.com/koppor/jabref/issues/277) +- We added a new cleanup operation that replaces ligatures with their expanded form. [3613](https://github.com/JabRef/jabref/issues/3613) ### Fixed - We fixed an issue where pressing space caused the cursor to jump to the start of the text field. [#3471](https://github.com/JabRef/jabref/issues/3471) diff --git a/src/main/java/org/jabref/logic/cleanup/Cleanups.java b/src/main/java/org/jabref/logic/cleanup/Cleanups.java index 17072cb723e..226e3406466 100644 --- a/src/main/java/org/jabref/logic/cleanup/Cleanups.java +++ b/src/main/java/org/jabref/logic/cleanup/Cleanups.java @@ -14,6 +14,7 @@ import org.jabref.logic.formatter.bibtexfields.OrdinalsToSuperscriptFormatter; import org.jabref.logic.formatter.bibtexfields.UnicodeToLatexFormatter; import org.jabref.logic.layout.format.LatexToUnicodeFormatter; +import org.jabref.logic.layout.format.ReplaceUnicodeLigaturesFormatter; import org.jabref.model.cleanup.FieldFormatterCleanup; import org.jabref.model.cleanup.FieldFormatterCleanups; import org.jabref.model.cleanup.Formatter; @@ -35,6 +36,7 @@ public class Cleanups { defaultFormatters.add(new FieldFormatterCleanup(FieldName.PAGES, new NormalizePagesFormatter())); defaultFormatters.add(new FieldFormatterCleanup(FieldName.DATE, new NormalizeDateFormatter())); defaultFormatters.add(new FieldFormatterCleanup(FieldName.MONTH, new NormalizeMonthFormatter())); + defaultFormatters.add(new FieldFormatterCleanup(FieldName.INTERNAL_ALL_TEXT_FIELDS_FIELD, new ReplaceUnicodeLigaturesFormatter())); DEFAULT_SAVE_ACTIONS = new FieldFormatterCleanups(false, defaultFormatters); List recommendedBibTeXFormatters = new ArrayList<>(); @@ -82,7 +84,7 @@ public static List parse(String formatterString) { while (startIndex < formatterString.length()) { // read the field name int currentIndex = remainingString.indexOf('['); - String fieldKey = remainingString.substring(0, currentIndex); + String fieldKey = remainingString.substring(0, currentIndex); int endIndex = remainingString.indexOf(']'); startIndex += endIndex + 1; @@ -125,7 +127,6 @@ public static FieldFormatterCleanups parse(List formatterMetaList) { // return default actions return DEFAULT_SAVE_ACTIONS; } - } private static Formatter getFormatterFromString(String formatterName) { diff --git a/src/main/java/org/jabref/logic/layout/format/ReplaceUnicodeLigaturesFormatter.java b/src/main/java/org/jabref/logic/layout/format/ReplaceUnicodeLigaturesFormatter.java new file mode 100644 index 00000000000..f51c2e7b084 --- /dev/null +++ b/src/main/java/org/jabref/logic/layout/format/ReplaceUnicodeLigaturesFormatter.java @@ -0,0 +1,53 @@ +package org.jabref.logic.layout.format; + +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Pattern; + +import org.jabref.logic.l10n.Localization; +import org.jabref.logic.layout.LayoutFormatter; +import org.jabref.logic.util.strings.UnicodeLigaturesMap; +import org.jabref.model.cleanup.Formatter; + +public class ReplaceUnicodeLigaturesFormatter implements LayoutFormatter, Formatter { + + private Map ligaturesMap; + + public ReplaceUnicodeLigaturesFormatter() { + ligaturesMap = new HashMap<>(); + UnicodeLigaturesMap stringMap = new UnicodeLigaturesMap(); + for (String key : stringMap.keySet()) { + ligaturesMap.put(Pattern.compile(key), stringMap.get(key)); + } + } + + @Override + public String getName() { + return Localization.lang("Replace Unicode ligatures"); + } + + @Override + public String getKey() { + return "remove_unicode_ligatures"; + } + + @Override + public String format(String fieldText) { + String result = fieldText; + + for (Pattern key : ligaturesMap.keySet()) { + result = key.matcher(result).replaceAll(ligaturesMap.get(key)); + } + return result; + } + + @Override + public String getDescription() { + return Localization.lang("Replaces Unicode ligatures with their expanded form"); + } + + @Override + public String getExampleInput() { + return "Æneas"; + } +} diff --git a/src/main/java/org/jabref/logic/util/strings/UnicodeLigaturesMap.java b/src/main/java/org/jabref/logic/util/strings/UnicodeLigaturesMap.java new file mode 100644 index 00000000000..77c54dec6b1 --- /dev/null +++ b/src/main/java/org/jabref/logic/util/strings/UnicodeLigaturesMap.java @@ -0,0 +1,68 @@ +package org.jabref.logic.util.strings; + +import java.util.HashMap; + +public class UnicodeLigaturesMap extends HashMap { + + /** + * Ligature mapping taken from https://en.wikipedia.org/wiki/Typographic_ligature#Ligatures_in_Unicode_(Latin_alphabets) + * + * The mapping is bijective. In case it is ever needed to turn the extended version back to unicode ligatures, the + * map can easily be reversed. + */ + public UnicodeLigaturesMap() { + put("\uA732", "AA"); + put("\uA733", "aa"); + put("\u00C6", "AE"); + put("\u00E6", "ae"); + put("\uA734", "AO"); + put("\uA735", "ao"); + put("\uA736", "AU"); + put("\uA737", "au"); + put("\uA738", "AV"); + put("\uA739", "av"); + //AV, av with bar + put("\uA73A", "AV"); + put("\uA73B", "av"); + put("\uA73C", "AY"); + put("\uA73D", "ay"); + put("\uD83D\uDE70", "et"); + put("\uFB00", "ff"); + put("\uFB01", "fi"); + put("\uFB02", "fl"); + put("\uFB03", "ffi"); + put("\uFB04", "ffl"); + put("\uFB05", "ſt"); + put("\uFB06", "st"); + put("\u0152", "OE"); + put("\u0153", "oe"); + put("\uA74E", "OO"); + put("\uA74F", "oo"); + // we explicitly decided to exclude the conversion of ß or ẞ + // put("\u1E9E", "ſs"); + // put("\u00DF", "ſz"); + put("\uA728", "TZ"); + put("\uA729", "tz"); + put("\u1D6B", "ue"); + put("\uA760", "VY"); + put("\uA761", "vy"); + + // ligatures for phonetic transcription + put("\u0238", "db"); + put("\u02A3", "dz"); + put("\u02A5", "dʑ"); + put("\u02A4", "dʒ"); + put("\u02A9", "fŋ"); + put("\u0132", "IJ"); + put("\u0133", "ij"); + put("\u02AA", "ls"); + put("\u02AB", "lz"); + put("\u026E", "lʒ"); + put("\u0239", "qp"); + put("\u02A6", "ts"); + put("\u02A7", "tʃ"); + put("\u02A8", "tɕ"); + put("\uAB50", "ui"); + put("\uAB51", "turned ui"); + } +} diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties index 0ac3e123a66..f9cc9db3029 100644 --- a/src/main/resources/l10n/JabRef_en.properties +++ b/src/main/resources/l10n/JabRef_en.properties @@ -994,6 +994,9 @@ Replace\ string=Replace string Replace\ with=Replace with +Replace\ Unicode\ ligatures=Replace Unicode ligatures +Replaces\ Unicode\ ligatures\ with\ their\ expanded\ form=Replaces Unicode ligatures with their expanded form + Replaced=Replaced Required\ fields=Required fields diff --git a/src/test/java/org/jabref/logic/layout/format/ReplaceUnicodeLigaturesFormatterTest.java b/src/test/java/org/jabref/logic/layout/format/ReplaceUnicodeLigaturesFormatterTest.java new file mode 100644 index 00000000000..987fc22153c --- /dev/null +++ b/src/test/java/org/jabref/logic/layout/format/ReplaceUnicodeLigaturesFormatterTest.java @@ -0,0 +1,38 @@ +package org.jabref.logic.layout.format; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class ReplaceUnicodeLigaturesFormatterTest { + + private ReplaceUnicodeLigaturesFormatter formatter; + + @BeforeEach + public void setUp() { + formatter = new ReplaceUnicodeLigaturesFormatter(); + } + + @Test + public void testPlainFormat() { + assertEquals("lorem ipsum", formatter.format("lorem ipsum")); + } + + @Test + public void testSingleLigatures() { + assertEquals("AA", formatter.format("\uA732")); + assertEquals("fi", formatter.format("fi")); + assertEquals("et", formatter.format("\uD83D\uDE70")); + } + + @Test + public void testLigatureSequence() { + assertEquals("aefffflstue", formatter.format("æfffflstᵫ")); + } + + @Test + public void testSampleInput() { + assertEquals("AEneas", formatter.format("Æneas")); + } +} From 9fac1e37c5654406f215c3359da029e965e4cb81 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Wed, 14 Feb 2018 15:31:42 +0100 Subject: [PATCH 27/94] New Crowdin translations (#3719) --- src/main/resources/l10n/JabRef_da.properties | 1 + src/main/resources/l10n/JabRef_de.properties | 1 + src/main/resources/l10n/JabRef_el.properties | 1 + src/main/resources/l10n/JabRef_es.properties | 1 + src/main/resources/l10n/JabRef_fa.properties | 1 + src/main/resources/l10n/JabRef_fr.properties | 1 + src/main/resources/l10n/JabRef_in.properties | 1 + src/main/resources/l10n/JabRef_it.properties | 1 + src/main/resources/l10n/JabRef_ja.properties | 1 + src/main/resources/l10n/JabRef_nl.properties | 1 + src/main/resources/l10n/JabRef_no.properties | 1 + src/main/resources/l10n/JabRef_pt_BR.properties | 1 + src/main/resources/l10n/JabRef_ru.properties | 1 + src/main/resources/l10n/JabRef_sv.properties | 1 + src/main/resources/l10n/JabRef_tr.properties | 1 + src/main/resources/l10n/JabRef_vi.properties | 1 + src/main/resources/l10n/JabRef_zh.properties | 1 + 17 files changed, 17 insertions(+) diff --git a/src/main/resources/l10n/JabRef_da.properties b/src/main/resources/l10n/JabRef_da.properties index dcc7edb6e26..38495a2215f 100644 --- a/src/main/resources/l10n/JabRef_da.properties +++ b/src/main/resources/l10n/JabRef_da.properties @@ -949,6 +949,7 @@ Replace\ string=Erstat streng Replace\ with=Erstat med + Replaced=Erstattet Required\ fields=Obligatoriske felter diff --git a/src/main/resources/l10n/JabRef_de.properties b/src/main/resources/l10n/JabRef_de.properties index 8ebcb797f23..194ea045c7b 100644 --- a/src/main/resources/l10n/JabRef_de.properties +++ b/src/main/resources/l10n/JabRef_de.properties @@ -994,6 +994,7 @@ Replace\ string=String ersetzen Replace\ with=Ersetzen durch + Replaced=Ersetzt\: Required\ fields=Benötigte Felder diff --git a/src/main/resources/l10n/JabRef_el.properties b/src/main/resources/l10n/JabRef_el.properties index e906478ffc7..ccffa7831b9 100644 --- a/src/main/resources/l10n/JabRef_el.properties +++ b/src/main/resources/l10n/JabRef_el.properties @@ -683,6 +683,7 @@ Open\ file=Άνοιγμα αρχείου + Forward=Επόμενο diff --git a/src/main/resources/l10n/JabRef_es.properties b/src/main/resources/l10n/JabRef_es.properties index a56d47284e9..1be1e1ba8c6 100644 --- a/src/main/resources/l10n/JabRef_es.properties +++ b/src/main/resources/l10n/JabRef_es.properties @@ -985,6 +985,7 @@ Replace\ string=Reemplazar cadena Replace\ with=Reemplazar con + Replaced=Reemplazado Required\ fields=Campos requeridos diff --git a/src/main/resources/l10n/JabRef_fa.properties b/src/main/resources/l10n/JabRef_fa.properties index b24a722d765..219a94504af 100644 --- a/src/main/resources/l10n/JabRef_fa.properties +++ b/src/main/resources/l10n/JabRef_fa.properties @@ -606,6 +606,7 @@ Open\ terminal\ here=در اینجا پایانه را باز کن + Forward=بعد diff --git a/src/main/resources/l10n/JabRef_fr.properties b/src/main/resources/l10n/JabRef_fr.properties index 2e2235994f8..a5627bb2300 100644 --- a/src/main/resources/l10n/JabRef_fr.properties +++ b/src/main/resources/l10n/JabRef_fr.properties @@ -994,6 +994,7 @@ Replace\ string=Remplacer la chaîne Replace\ with=Remplacer par + Replaced=Remplacé Required\ fields=Champs requis diff --git a/src/main/resources/l10n/JabRef_in.properties b/src/main/resources/l10n/JabRef_in.properties index 3a4c9c60577..f6d46c7879d 100644 --- a/src/main/resources/l10n/JabRef_in.properties +++ b/src/main/resources/l10n/JabRef_in.properties @@ -994,6 +994,7 @@ Replace\ string=Ganti string Replace\ with=Ganti dengan + Replaced=Diganti Required\ fields=Bidang diperlukan diff --git a/src/main/resources/l10n/JabRef_it.properties b/src/main/resources/l10n/JabRef_it.properties index 14c6a870d2f..c062730567d 100644 --- a/src/main/resources/l10n/JabRef_it.properties +++ b/src/main/resources/l10n/JabRef_it.properties @@ -989,6 +989,7 @@ Replace\ string=Sostituisci stringa Replace\ with=Sostituisci con + Replaced=Sostituito Required\ fields=Campo obbligatorio diff --git a/src/main/resources/l10n/JabRef_ja.properties b/src/main/resources/l10n/JabRef_ja.properties index 3430eff87fc..dba7ca990de 100644 --- a/src/main/resources/l10n/JabRef_ja.properties +++ b/src/main/resources/l10n/JabRef_ja.properties @@ -994,6 +994,7 @@ Replace\ string=文字列の置換 Replace\ with=置換文字列 + Replaced=置換しました Required\ fields=必須フィールド diff --git a/src/main/resources/l10n/JabRef_nl.properties b/src/main/resources/l10n/JabRef_nl.properties index 64b408556fc..fb74a7317a8 100644 --- a/src/main/resources/l10n/JabRef_nl.properties +++ b/src/main/resources/l10n/JabRef_nl.properties @@ -879,6 +879,7 @@ Replace\ string=Tekst vervangen Replace\ with=Vervang door + Replaced=Vervangen Required\ fields=Vereiste velden diff --git a/src/main/resources/l10n/JabRef_no.properties b/src/main/resources/l10n/JabRef_no.properties index 1b03943f402..22253c3d7fd 100644 --- a/src/main/resources/l10n/JabRef_no.properties +++ b/src/main/resources/l10n/JabRef_no.properties @@ -946,6 +946,7 @@ Replace\ string=Erstatt streng Replace\ with=Erstatt med + Replaced=Erstattet Required\ fields=Nødvendige felter diff --git a/src/main/resources/l10n/JabRef_pt_BR.properties b/src/main/resources/l10n/JabRef_pt_BR.properties index 79aac274e23..ff8647825e0 100644 --- a/src/main/resources/l10n/JabRef_pt_BR.properties +++ b/src/main/resources/l10n/JabRef_pt_BR.properties @@ -957,6 +957,7 @@ Replace\ string=Substituir string Replace\ with=Substituir por + Replaced=Substituído Required\ fields=Campos obrigatórios diff --git a/src/main/resources/l10n/JabRef_ru.properties b/src/main/resources/l10n/JabRef_ru.properties index 81f16e0bfd9..48ff84e75fd 100644 --- a/src/main/resources/l10n/JabRef_ru.properties +++ b/src/main/resources/l10n/JabRef_ru.properties @@ -964,6 +964,7 @@ Replace\ string=Заменить строку Replace\ with=Заменить на + Replaced=Заменено Required\ fields=Обязательные поля diff --git a/src/main/resources/l10n/JabRef_sv.properties b/src/main/resources/l10n/JabRef_sv.properties index ceb763d0138..22b73f393a9 100644 --- a/src/main/resources/l10n/JabRef_sv.properties +++ b/src/main/resources/l10n/JabRef_sv.properties @@ -924,6 +924,7 @@ Replace\ string=Ersätt sträng Replace\ with=Ersätt med + Replaced=Ersatte Required\ fields=Obligatoriska fält diff --git a/src/main/resources/l10n/JabRef_tr.properties b/src/main/resources/l10n/JabRef_tr.properties index 33cea7050cf..fe48ab4f42f 100644 --- a/src/main/resources/l10n/JabRef_tr.properties +++ b/src/main/resources/l10n/JabRef_tr.properties @@ -993,6 +993,7 @@ Replace\ string=Dizgenin yerine koy Replace\ with=Şununla değiştir + Replaced=Değiştirildi Required\ fields=Zorunlu alanlar diff --git a/src/main/resources/l10n/JabRef_vi.properties b/src/main/resources/l10n/JabRef_vi.properties index 90dc5e85d17..ff713e1db72 100644 --- a/src/main/resources/l10n/JabRef_vi.properties +++ b/src/main/resources/l10n/JabRef_vi.properties @@ -971,6 +971,7 @@ Replace\ string=Thay thế chuỗi Replace\ with=Thay thế bởi + Replaced=Bị thay thế Required\ fields=Các dữ liệu cần có diff --git a/src/main/resources/l10n/JabRef_zh.properties b/src/main/resources/l10n/JabRef_zh.properties index 52305697da7..6501515b830 100644 --- a/src/main/resources/l10n/JabRef_zh.properties +++ b/src/main/resources/l10n/JabRef_zh.properties @@ -984,6 +984,7 @@ Replace\ string=替换字符串 Replace\ with=替换为 + Replaced=被替换 Required\ fields=必选域 From d9e8c2a6c154ca21efff0c66b19a8a3a8eee0690 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Thu, 15 Feb 2018 07:46:13 +0100 Subject: [PATCH 28/94] Add changelog for #3708 --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 951f4220d01..3ee76eb77a2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,7 +28,8 @@ For more details refer to the [field mapping help page](http://help.jabref.org/e - We changed the default dialog option when removing a [file link](http://help.jabref.org/en/FileLinks#adding-external-links-to-an-entry) from an entry. The new default removes the linked file from the entry instead of deleting the file from disk. [#3679](https://github.com/JabRef/jabref/issues/3679) - The group editing window can now also be called by double-clicking the group to be edited. [koppor#277](https://github.com/koppor/jabref/issues/277) -- We added a new cleanup operation that replaces ligatures with their expanded form. [3613](https://github.com/JabRef/jabref/issues/3613) +- The magnifier icon at the search shows the [search mode](https://help.jabref.org/en/Search#search-modes) again. [#3535](https://github.com/JabRef/jabref/issues/3535) +- We added a new cleanup operation that replaces ligatures with their expanded form. [#3613](https://github.com/JabRef/jabref/issues/3613) ### Fixed - We fixed an issue where pressing space caused the cursor to jump to the start of the text field. [#3471](https://github.com/JabRef/jabref/issues/3471) From 566918e124fd569583cd330d971fcc660ac13903 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Thu, 15 Feb 2018 08:41:37 +0100 Subject: [PATCH 29/94] New translations JabRef_en.properties (French) --- src/main/resources/l10n/JabRef_fr.properties | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/resources/l10n/JabRef_fr.properties b/src/main/resources/l10n/JabRef_fr.properties index a5627bb2300..57607b07972 100644 --- a/src/main/resources/l10n/JabRef_fr.properties +++ b/src/main/resources/l10n/JabRef_fr.properties @@ -387,6 +387,7 @@ Edit\ entry=Editer l'entrée Save\ file=Editer le lien de fichier Edit\ file\ type=Editer le type de fichier +Add\ group=Ajouter un groupe Edit\ group=Editer le groupe @@ -994,6 +995,8 @@ Replace\ string=Remplacer la chaîne Replace\ with=Remplacer par +Replace\ Unicode\ ligatures=Remplacer les ligatures Unicode +Replaces\ Unicode\ ligatures\ with\ their\ expanded\ form=Remplace les ligatures Unicode par leur forme développée Replaced=Remplacé From 18d40f4ecde0bcf2e43fd7c5e8680e8de63628fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Lenhard?= Date: Thu, 15 Feb 2018 09:46:17 +0100 Subject: [PATCH 30/94] Update entry editor when entry type changes (#3714) --- CHANGELOG.md | 1 + .../jabref/gui/entryeditor/EntryEditor.java | 21 ++++++++++++++++++- .../gui/entryeditor/EntryEditorTab.java | 9 +++++++- .../java/org/jabref/model/entry/BibEntry.java | 16 +++++++++----- 4 files changed, 40 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ee76eb77a2..636d3041886 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ The new default removes the linked file from the entry instead of deleting the f - We added a new cleanup operation that replaces ligatures with their expanded form. [#3613](https://github.com/JabRef/jabref/issues/3613) ### Fixed +- We fixed an issue where changing the type of an entry did not update the label in the tool bar of the entry editor and the contents of the currently visible entry editor tab - We fixed an issue where pressing space caused the cursor to jump to the start of the text field. [#3471](https://github.com/JabRef/jabref/issues/3471) - We fixed the missing dot in the name of an exported file. [#3576](https://github.com/JabRef/jabref/issues/3576) - Autocompletion in the search bar can now be disabled via the preferences. [#3598](https://github.com/JabRef/jabref/issues/3598) diff --git a/src/main/java/org/jabref/gui/entryeditor/EntryEditor.java b/src/main/java/org/jabref/gui/entryeditor/EntryEditor.java index dbaa8ca93ed..87e151a3e3f 100644 --- a/src/main/java/org/jabref/gui/entryeditor/EntryEditor.java +++ b/src/main/java/org/jabref/gui/entryeditor/EntryEditor.java @@ -38,6 +38,7 @@ import org.jabref.preferences.JabRefPreferences; import org.fxmisc.easybind.EasyBind; +import org.fxmisc.easybind.Subscription; /** * GUI component that allows editing of the fields of a BibEntry (i.e. the @@ -55,6 +56,7 @@ public class EntryEditor extends BorderPane { private final CountingUndoManager undoManager; private final BasePanel panel; private final List searchListeners = new ArrayList<>(); + private Subscription typeSubscription; private final List tabs; /** * A reference to the entry this editor works on. @@ -210,7 +212,13 @@ public BibEntry getEntry() { * Sets the entry to edit. */ public void setEntry(BibEntry entry) { - this.entry = Objects.requireNonNull(entry); + Objects.requireNonNull(entry); + + // remove subscription for old entry if existing + if (typeSubscription != null) { + typeSubscription.unsubscribe(); + } + this.entry = entry; DefaultTaskExecutor.runInJavaFXThread(() -> { recalculateVisibleTabs(); @@ -224,6 +232,16 @@ public void setEntry(BibEntry entry) { setupToolBar(); }); + + // subscribe to type changes for rebuilding the currently visible tab + typeSubscription = EasyBind.subscribe(this.entry.typeProperty(), type -> { + DefaultTaskExecutor.runInJavaFXThread(() -> { + typeLabel.setText(new TypedBibEntry(entry, bibDatabaseContext.getMode()).getTypeForDisplay()); + recalculateVisibleTabs(); + EntryEditorTab selectedTab = (EntryEditorTab) tabbed.getSelectionModel().getSelectedItem(); + selectedTab.notifyAboutFocus(entry); + }); + }); } private void setupToolBar() { @@ -264,4 +282,5 @@ public void setFocusToField(String fieldName) { } }); } + } diff --git a/src/main/java/org/jabref/gui/entryeditor/EntryEditorTab.java b/src/main/java/org/jabref/gui/entryeditor/EntryEditorTab.java index ebc4fef4629..550fbcaba99 100644 --- a/src/main/java/org/jabref/gui/entryeditor/EntryEditorTab.java +++ b/src/main/java/org/jabref/gui/entryeditor/EntryEditorTab.java @@ -9,6 +9,11 @@ public abstract class EntryEditorTab extends Tab { protected BibEntry currentEntry; + /** + * Needed to track for which type of entry this tab was build and to rebuild it if the type changes + */ + private String currentEntryType = ""; + /** * Decide whether to show this tab for the given entry. */ @@ -31,10 +36,12 @@ protected void handleFocus() { * Notifies the tab that it got focus and should display the given entry. */ public void notifyAboutFocus(BibEntry entry) { - if (!entry.equals(currentEntry)) { + if (!entry.equals(currentEntry) || !currentEntryType.equals(entry.getType())) { currentEntry = entry; + currentEntryType = entry.getType(); DefaultTaskExecutor.runInJavaFXThread(() -> bindToEntry(entry)); } handleFocus(); } + } diff --git a/src/main/java/org/jabref/model/entry/BibEntry.java b/src/main/java/org/jabref/model/entry/BibEntry.java index c87a73bdd3b..68b237ad46b 100644 --- a/src/main/java/org/jabref/model/entry/BibEntry.java +++ b/src/main/java/org/jabref/model/entry/BibEntry.java @@ -17,6 +17,8 @@ import javafx.beans.binding.Bindings; import javafx.beans.binding.ObjectBinding; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; import javafx.collections.FXCollections; import javafx.collections.ObservableMap; @@ -56,7 +58,7 @@ public class BibEntry implements Cloneable { private final Map latexFreeFields = new ConcurrentHashMap<>(); private final EventBus eventBus = new EventBus(); private String id; - private String type; + private StringProperty type = new SimpleStringProperty(); private ObservableMap fields = FXCollections.observableMap(new ConcurrentHashMap<>()); // Search and grouping status is stored in boolean fields for quick reference: private boolean searchHit; @@ -200,6 +202,10 @@ public boolean hasCiteKey() { * Returns this entry's type. */ public String getType() { + return type.getValue(); + } + + public StringProperty typeProperty() { return type; } @@ -232,7 +238,7 @@ public Optional setType(String type, EntryEventSource eventSource) return Optional.empty(); } - this.type = newType.toLowerCase(Locale.ENGLISH); + this.type.setValue(newType.toLowerCase(Locale.ENGLISH)); changed = true; FieldChange change = new FieldChange(this, TYPE_HEADER, oldType, newType); @@ -528,7 +534,7 @@ private boolean atLeastOnePresent(String[] fieldsToCheck, BibDatabase database) */ @Override public Object clone() { - BibEntry clone = new BibEntry(type); + BibEntry clone = new BibEntry(type.getValue()); clone.fields = FXCollections.observableMap(new ConcurrentHashMap<>(fields)); return clone; } @@ -716,14 +722,14 @@ public boolean equals(Object o) { return false; } BibEntry entry = (BibEntry) o; - return Objects.equals(type, entry.type) + return Objects.equals(type.getValue(), entry.type.getValue()) && Objects.equals(fields, entry.fields) && Objects.equals(commentsBeforeEntry, entry.commentsBeforeEntry); } @Override public int hashCode() { - return Objects.hash(type, fields); + return Objects.hash(type.getValue(), fields); } public void registerListener(Object object) { From b22940cdc1d81dcbe4a15d66f046fb95432072f0 Mon Sep 17 00:00:00 2001 From: Linus Dietz Date: Thu, 15 Feb 2018 14:27:41 +0100 Subject: [PATCH 31/94] Avoid unused private fields such as 'highlightPattern'. --- src/main/java/org/jabref/gui/PreviewPanel.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/org/jabref/gui/PreviewPanel.java b/src/main/java/org/jabref/gui/PreviewPanel.java index 33f73d3e58d..088c258bbd5 100644 --- a/src/main/java/org/jabref/gui/PreviewPanel.java +++ b/src/main/java/org/jabref/gui/PreviewPanel.java @@ -57,7 +57,6 @@ public class PreviewPanel extends ScrollPane implements SearchQueryHighlightList */ private Optional bibEntry = Optional.empty(); - private Optional highlightPattern = Optional.empty(); /** * If a database is set, the preview will attempt to resolve strings in the previewed entry using that database. */ @@ -265,7 +264,6 @@ private void setPreviewLabel(String text) { @Override public void highlightPattern(Optional newPattern) { // TODO: Implement that search phrases are highlighted - this.highlightPattern = newPattern; update(); } From fe268234dc900cda896038e994c65f94a0c82712 Mon Sep 17 00:00:00 2001 From: Linus Dietz Date: Thu, 15 Feb 2018 14:28:44 +0100 Subject: [PATCH 32/94] Document empty method body --- src/main/java/org/jabref/gui/fieldeditors/EditorTextArea.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jabref/gui/fieldeditors/EditorTextArea.java b/src/main/java/org/jabref/gui/fieldeditors/EditorTextArea.java index 19a98457601..6f783e05d06 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/EditorTextArea.java +++ b/src/main/java/org/jabref/gui/fieldeditors/EditorTextArea.java @@ -67,6 +67,6 @@ public void populateContextMenu(ContextMenu contextMenu) { @Override public void initialize(URL location, ResourceBundle resources) { - + // not needed } } From 83590155fb685b129fe5bde6d8baa2f990274da4 Mon Sep 17 00:00:00 2001 From: Linus Dietz Date: Thu, 15 Feb 2018 14:31:57 +0100 Subject: [PATCH 33/94] Avoid empty if statements --- .../java/org/jabref/gui/fieldeditors/LinkedFileViewModel.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jabref/gui/fieldeditors/LinkedFileViewModel.java b/src/main/java/org/jabref/gui/fieldeditors/LinkedFileViewModel.java index 490ccaa05f3..a3d7ae476e7 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/LinkedFileViewModel.java +++ b/src/main/java/org/jabref/gui/fieldeditors/LinkedFileViewModel.java @@ -328,13 +328,13 @@ public void writeXMPMetadata() { Optional file = linkedFile.findIn(databaseContext, Globals.prefs.getFileDirectoryPreferences()); if (!file.isPresent()) { // TODO: Print error message - // Localization.lang("PDF does not exist"); + LOGGER.warn("PDF does not exist!"); } else { try { XMPUtil.writeXMP(file.get(), entry, databaseContext.getDatabase(), Globals.prefs.getXMPPreferences()); } catch (IOException | TransformerException ex) { // TODO: Print error message - // Localization.lang("Error while writing") + " '" + file.toString() + "': " + ex; + LOGGER.warn("Error while writing" + " '" + file.toString() + "': " + ex); } } return null; From c7832fa0df4bba793821e2a485e854a47f86b0c2 Mon Sep 17 00:00:00 2001 From: Linus Dietz Date: Thu, 15 Feb 2018 14:33:15 +0100 Subject: [PATCH 34/94] Document empty method body --- src/main/java/org/jabref/gui/fieldeditors/TextArea.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/jabref/gui/fieldeditors/TextArea.java b/src/main/java/org/jabref/gui/fieldeditors/TextArea.java index 3b9c42436ad..958c0f9a21e 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/TextArea.java +++ b/src/main/java/org/jabref/gui/fieldeditors/TextArea.java @@ -67,7 +67,7 @@ public void setFieldName(String newName) { @Override public void setBackground(Color color) { - + //not needed } @Override @@ -124,12 +124,12 @@ public void setText(String newText) { @Override public void append(String text) { - + // not needed } @Override public void setEnabled(boolean enabled) { - + // not needed } @Override @@ -156,6 +156,6 @@ public void redo() { @Override public void requestFocus() { - + // not needed } } From dba4a41c625187ef19775485894bdd1dc0bccd2c Mon Sep 17 00:00:00 2001 From: Linus Dietz Date: Thu, 15 Feb 2018 14:38:50 +0100 Subject: [PATCH 35/94] access private, Avoid unused private fields --- .../java/org/jabref/gui/groups/GroupTreeNodeViewModel.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/main/java/org/jabref/gui/groups/GroupTreeNodeViewModel.java b/src/main/java/org/jabref/gui/groups/GroupTreeNodeViewModel.java index 9293bd63d52..82cebaf83f9 100644 --- a/src/main/java/org/jabref/gui/groups/GroupTreeNodeViewModel.java +++ b/src/main/java/org/jabref/gui/groups/GroupTreeNodeViewModel.java @@ -9,14 +9,12 @@ import java.util.List; import java.util.function.Consumer; -import javax.swing.Icon; import javax.swing.JTree; import javax.swing.tree.TreeNode; import javax.swing.tree.TreePath; import javax.swing.undo.AbstractUndoableEdit; import javax.swing.undo.UndoManager; -import org.jabref.gui.IconTheme; import org.jabref.gui.undo.CountingUndoManager; import org.jabref.model.FieldChange; import org.jabref.model.entry.BibEntry; @@ -33,11 +31,8 @@ public class GroupTreeNodeViewModel implements Transferable, TreeNode { - public static final DataFlavor FLAVOR; + private static final DataFlavor FLAVOR; private static final Logger LOGGER = LoggerFactory.getLogger(GroupTreeNodeViewModel.class); - private static final Icon GROUP_REFINING_ICON = IconTheme.JabRefIcon.GROUP_REFINING.getSmallIcon(); - private static final Icon GROUP_INCLUDING_ICON = IconTheme.JabRefIcon.GROUP_INCLUDING.getSmallIcon(); - private static final Icon GROUP_REGULAR_ICON = null; private static final DataFlavor[] FLAVORS; static { From 8c0b3660c7f6aa686ea1c93e848392f85b7136d4 Mon Sep 17 00:00:00 2001 From: Linus Dietz Date: Thu, 15 Feb 2018 15:26:34 +0100 Subject: [PATCH 36/94] Revert "Avoid empty if statements" This reverts commit 8359015 --- .../java/org/jabref/gui/fieldeditors/LinkedFileViewModel.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jabref/gui/fieldeditors/LinkedFileViewModel.java b/src/main/java/org/jabref/gui/fieldeditors/LinkedFileViewModel.java index a3d7ae476e7..490ccaa05f3 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/LinkedFileViewModel.java +++ b/src/main/java/org/jabref/gui/fieldeditors/LinkedFileViewModel.java @@ -328,13 +328,13 @@ public void writeXMPMetadata() { Optional file = linkedFile.findIn(databaseContext, Globals.prefs.getFileDirectoryPreferences()); if (!file.isPresent()) { // TODO: Print error message - LOGGER.warn("PDF does not exist!"); + // Localization.lang("PDF does not exist"); } else { try { XMPUtil.writeXMP(file.get(), entry, databaseContext.getDatabase(), Globals.prefs.getXMPPreferences()); } catch (IOException | TransformerException ex) { // TODO: Print error message - LOGGER.warn("Error while writing" + " '" + file.toString() + "': " + ex); + // Localization.lang("Error while writing") + " '" + file.toString() + "': " + ex; } } return null; From 4b0e0ad644812ec0d5cafebceb96d5ddac9c53e1 Mon Sep 17 00:00:00 2001 From: Linus Dietz Date: Thu, 15 Feb 2018 15:30:30 +0100 Subject: [PATCH 37/94] Avoid unused constructor parameters --- src/main/java/org/jabref/gui/fieldeditors/OptionEditor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jabref/gui/fieldeditors/OptionEditor.java b/src/main/java/org/jabref/gui/fieldeditors/OptionEditor.java index 1b97d7be35f..0e500531b2e 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/OptionEditor.java +++ b/src/main/java/org/jabref/gui/fieldeditors/OptionEditor.java @@ -17,7 +17,7 @@ public class OptionEditor extends HBox implements FieldEditorFX { @FXML private OptionEditorViewModel viewModel; @FXML private ComboBox comboBox; - public OptionEditor(String fieldName, OptionEditorViewModel viewModel) { + public OptionEditor(OptionEditorViewModel viewModel) { this.viewModel = viewModel; ControlHelper.loadFXMLForControl(this); From 56bd2b2db2ef6024b227ce9563cb28d6f40f08a3 Mon Sep 17 00:00:00 2001 From: Linus Dietz Date: Thu, 15 Feb 2018 15:31:46 +0100 Subject: [PATCH 38/94] Avoid unused private fields --- src/main/java/org/jabref/gui/search/SearchResultFrame.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/org/jabref/gui/search/SearchResultFrame.java b/src/main/java/org/jabref/gui/search/SearchResultFrame.java index 322fc2a4d10..18639b5c93f 100644 --- a/src/main/java/org/jabref/gui/search/SearchResultFrame.java +++ b/src/main/java/org/jabref/gui/search/SearchResultFrame.java @@ -2,7 +2,6 @@ import java.awt.BorderLayout; import java.awt.Color; -import java.awt.Rectangle; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ComponentAdapter; @@ -101,7 +100,6 @@ public class SearchResultFrame { private final JSplitPane contentPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT); - private final Rectangle toRect = new Rectangle(0, 0, 1, 1); private final EventList entries = new BasicEventList<>(); private final Map entryHome = new HashMap<>(); From d8096817aae405c2f3e6b71f84ddfaa71adba580 Mon Sep 17 00:00:00 2001 From: Linus Dietz Date: Thu, 15 Feb 2018 15:34:10 +0100 Subject: [PATCH 39/94] Avoid unused method --- .../org/jabref/gui/fieldeditors/FieldEditors.java | 14 +++++++------- .../org/jabref/logic/exporter/GroupSerializer.java | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/jabref/gui/fieldeditors/FieldEditors.java b/src/main/java/org/jabref/gui/fieldeditors/FieldEditors.java index d65544ae392..c292a009ffa 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/FieldEditors.java +++ b/src/main/java/org/jabref/gui/fieldeditors/FieldEditors.java @@ -53,20 +53,20 @@ public static FieldEditorFX getForField(String fieldName, TaskExecutor taskExecu } else if (fieldExtras.contains(FieldProperty.FILE_EDITOR)) { return new LinkedFilesEditor(fieldName, dialogService, databaseContext, taskExecutor, suggestionProvider, fieldCheckers); } else if (fieldExtras.contains(FieldProperty.YES_NO)) { - return new OptionEditor<>(fieldName, new YesNoEditorViewModel(fieldName, suggestionProvider, fieldCheckers)); + return new OptionEditor<>(new YesNoEditorViewModel(fieldName, suggestionProvider, fieldCheckers)); } else if (fieldExtras.contains(FieldProperty.MONTH)) { - return new OptionEditor<>(fieldName, new MonthEditorViewModel(fieldName, suggestionProvider, databaseContext.getMode(), fieldCheckers)); + return new OptionEditor<>(new MonthEditorViewModel(fieldName, suggestionProvider, databaseContext.getMode(), fieldCheckers)); } else if (fieldExtras.contains(FieldProperty.GENDER)) { - return new OptionEditor<>(fieldName, new GenderEditorViewModel(fieldName, suggestionProvider, fieldCheckers)); + return new OptionEditor<>(new GenderEditorViewModel(fieldName, suggestionProvider, fieldCheckers)); } else if (fieldExtras.contains(FieldProperty.EDITOR_TYPE)) { - return new OptionEditor<>(fieldName, new EditorTypeEditorViewModel(fieldName, suggestionProvider, fieldCheckers)); + return new OptionEditor<>(new EditorTypeEditorViewModel(fieldName, suggestionProvider, fieldCheckers)); } else if (fieldExtras.contains(FieldProperty.PAGINATION)) { - return new OptionEditor<>(fieldName, new PaginationEditorViewModel(fieldName, suggestionProvider, fieldCheckers)); + return new OptionEditor<>(new PaginationEditorViewModel(fieldName, suggestionProvider, fieldCheckers)); } else if (fieldExtras.contains(FieldProperty.TYPE)) { if ("patent".equalsIgnoreCase(entryType)) { - return new OptionEditor<>(fieldName, new PatentTypeEditorViewModel(fieldName, suggestionProvider, fieldCheckers)); + return new OptionEditor<>(new PatentTypeEditorViewModel(fieldName, suggestionProvider, fieldCheckers)); } else { - return new OptionEditor<>(fieldName, new TypeEditorViewModel(fieldName, suggestionProvider, fieldCheckers)); + return new OptionEditor<>(new TypeEditorViewModel(fieldName, suggestionProvider, fieldCheckers)); } } else if (fieldExtras.contains(FieldProperty.SINGLE_ENTRY_LINK) || fieldExtras.contains(FieldProperty.MULTIPLE_ENTRY_LINK)) { return new LinkedEntriesEditor(fieldName, databaseContext, suggestionProvider, fieldCheckers); diff --git a/src/main/java/org/jabref/logic/exporter/GroupSerializer.java b/src/main/java/org/jabref/logic/exporter/GroupSerializer.java index eed98ed454c..4e9d5e196e8 100644 --- a/src/main/java/org/jabref/logic/exporter/GroupSerializer.java +++ b/src/main/java/org/jabref/logic/exporter/GroupSerializer.java @@ -21,7 +21,7 @@ import org.jabref.model.strings.StringUtil; public class GroupSerializer { - private static String serializeAllEntriesGroup(AllEntriesGroup group) { + private static String serializeAllEntriesGroup() { return MetadataSerializationConfiguration.ALL_ENTRIES_GROUP_ID; } @@ -115,7 +115,7 @@ public List serializeTree(GroupTreeNode node) { private String serializeGroup(AbstractGroup group) { if (group instanceof AllEntriesGroup) { - return serializeAllEntriesGroup((AllEntriesGroup)group); + return serializeAllEntriesGroup(); } else if (group instanceof ExplicitGroup) { return serializeExplicitGroup((ExplicitGroup)group); } else if (group instanceof KeywordGroup) { From 483fd0864abf1c246117ba06628ce21d4340705c Mon Sep 17 00:00:00 2001 From: Linus Dietz Date: Thu, 15 Feb 2018 15:38:29 +0100 Subject: [PATCH 40/94] Inline field --- .../java/org/jabref/logic/bibtex/FieldContentParserTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/org/jabref/logic/bibtex/FieldContentParserTest.java b/src/test/java/org/jabref/logic/bibtex/FieldContentParserTest.java index 0c973a6aed2..b63242b6f30 100644 --- a/src/test/java/org/jabref/logic/bibtex/FieldContentParserTest.java +++ b/src/test/java/org/jabref/logic/bibtex/FieldContentParserTest.java @@ -12,11 +12,11 @@ public class FieldContentParserTest { private FieldContentParser parser; - private FieldContentParserPreferences prefs; + @BeforeEach public void setUp() throws Exception { - prefs = new FieldContentParserPreferences(Collections.emptyList()); + FieldContentParserPreferences prefs = new FieldContentParserPreferences(Collections.emptyList()); parser = new FieldContentParser(prefs); } From b2c2f13c6f1b063e09d41389935908dffd89ddc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Lenhard?= Date: Thu, 15 Feb 2018 16:27:14 +0100 Subject: [PATCH 41/94] Refactor deprecated part of ProtectedTermsFormatter (#3720) * Refactor deprecated part of ProtectedTermsFormatter * Use static parameter class for formatter initialization * Provide a way to create an empty ProtectedTermsLoader * Remove instance variable for available formatters * Move from public instance variables to getters * Extracts ProtectedTermsFormatter from the Formatters/Cleanup framework * Minor refactorings * Directly return list from Formatters * Filter ProtectedTermsLists in lambda --- src/main/java/org/jabref/JabRefMain.java | 2 - src/main/java/org/jabref/gui/JabRefFrame.java | 4 +- .../cleanup/FieldFormatterCleanupsPanel.java | 11 +++-- .../contextmenu/CaseChangeMenu.java | 9 +++- .../contextmenu/ConversionMenu.java | 2 +- .../contextmenu/ProtectedTermsMenu.java | 35 ++++++++------ .../importer/fetcher/ACMPortalFetcher.java | 5 +- .../importer/fetcher/IEEEXploreFetcher.java | 3 +- .../protectedterms/ProtectedTermsDialog.java | 4 +- .../org/jabref/logic/cleanup/Cleanups.java | 11 ++--- .../jabref/logic/formatter/Formatters.java | 46 +++++++++++++------ .../casechanger/ProtectTermsFormatter.java | 24 ++-------- .../protectedterms/ProtectedTermsLoader.java | 9 ---- .../jabref/logic/formatter/FormatterTest.java | 2 - .../ProtectTermsFormatterTest.java | 4 +- 15 files changed, 84 insertions(+), 87 deletions(-) diff --git a/src/main/java/org/jabref/JabRefMain.java b/src/main/java/org/jabref/JabRefMain.java index f16e4dccf43..8ad2341544c 100644 --- a/src/main/java/org/jabref/JabRefMain.java +++ b/src/main/java/org/jabref/JabRefMain.java @@ -13,7 +13,6 @@ import org.jabref.cli.ArgumentProcessor; import org.jabref.gui.remote.JabRefMessageHandler; import org.jabref.logic.exporter.ExporterFactory; -import org.jabref.logic.formatter.casechanger.ProtectTermsFormatter; import org.jabref.logic.journals.JournalAbbreviationLoader; import org.jabref.logic.l10n.Localization; import org.jabref.logic.net.ProxyAuthenticator; @@ -151,7 +150,6 @@ private static void start(String[] args) { // Initialize protected terms loader Globals.protectedTermsLoader = new ProtectedTermsLoader(Globals.prefs.getProtectedTermsPreferences()); - ProtectTermsFormatter.setProtectedTermsLoader(Globals.protectedTermsLoader); // Check for running JabRef RemotePreferences remotePreferences = Globals.prefs.getRemotePreferences(); diff --git a/src/main/java/org/jabref/gui/JabRefFrame.java b/src/main/java/org/jabref/gui/JabRefFrame.java index 47db19b25e3..4abf2fbfe38 100644 --- a/src/main/java/org/jabref/gui/JabRefFrame.java +++ b/src/main/java/org/jabref/gui/JabRefFrame.java @@ -174,7 +174,6 @@ public class JabRefFrame extends JFrame implements OutputPrinter { private final OpenDatabaseAction open = new OpenDatabaseAction(this, true); private final EditModeAction editModeAction = new EditModeAction(); - // Here we instantiate menu/toolbar actions. Actions regarding // the currently open database are defined as a GeneralAction // with a unique command string. This causes the appropriate @@ -2210,8 +2209,7 @@ public ProtectedTermsAction() { @Override public void actionPerformed(ActionEvent e) { - ProtectedTermsDialog protectTermsDialog = new ProtectedTermsDialog(JabRefFrame.this, - Globals.protectedTermsLoader); + ProtectedTermsDialog protectTermsDialog = new ProtectedTermsDialog(JabRefFrame.this); protectTermsDialog.setVisible(true); } } diff --git a/src/main/java/org/jabref/gui/cleanup/FieldFormatterCleanupsPanel.java b/src/main/java/org/jabref/gui/cleanup/FieldFormatterCleanupsPanel.java index 97599ce1915..36c2150a201 100644 --- a/src/main/java/org/jabref/gui/cleanup/FieldFormatterCleanupsPanel.java +++ b/src/main/java/org/jabref/gui/cleanup/FieldFormatterCleanupsPanel.java @@ -25,8 +25,10 @@ import javax.swing.event.ListDataEvent; import javax.swing.event.ListDataListener; +import org.jabref.Globals; import org.jabref.JabRefGUI; import org.jabref.logic.cleanup.Cleanups; +import org.jabref.logic.formatter.casechanger.ProtectTermsFormatter; import org.jabref.logic.l10n.Localization; import org.jabref.model.cleanup.FieldFormatterCleanup; import org.jabref.model.cleanup.FieldFormatterCleanups; @@ -54,11 +56,14 @@ public class FieldFormatterCleanupsPanel extends JPanel { private JButton recommendButton; private final FieldFormatterCleanups defaultFormatters; + private List availableFormatters; public FieldFormatterCleanupsPanel(String description, FieldFormatterCleanups defaultFormatters) { this.defaultFormatters = Objects.requireNonNull(defaultFormatters); cleanupEnabled = new JCheckBox(description); + availableFormatters = Cleanups.getBuiltInFormatters(); + availableFormatters.add(new ProtectTermsFormatter(Globals.protectedTermsLoader)); } public void setValues(MetaData metaData) { @@ -218,9 +223,9 @@ private JPanel getSelectorPanel() { selectFieldCombobox.setEditable(true); builder.add(selectFieldCombobox).xy(1, 1); - List formatterNames = Cleanups.getAvailableFormatters().stream() + List formatterNames = availableFormatters.stream() .map(Formatter::getName).collect(Collectors.toList()); - List formatterDescriptions = Cleanups.getAvailableFormatters().stream() + List formatterDescriptions = availableFormatters.stream() .map(Formatter::getDescription).collect(Collectors.toList()); formattersCombobox = new JComboBox<>(formatterNames.toArray()); formattersCombobox.setRenderer(new DefaultListCellRenderer() { @@ -291,7 +296,7 @@ private FieldFormatterCleanup getFieldFormatterCleanup() { private Formatter getFieldFormatter() { Formatter selectedFormatter = null; String selectedFormatterName = formattersCombobox.getSelectedItem().toString(); - for (Formatter formatter : Cleanups.getAvailableFormatters()) { + for (Formatter formatter : availableFormatters) { if (formatter.getName().equals(selectedFormatterName)) { selectedFormatter = formatter; break; diff --git a/src/main/java/org/jabref/gui/fieldeditors/contextmenu/CaseChangeMenu.java b/src/main/java/org/jabref/gui/fieldeditors/contextmenu/CaseChangeMenu.java index 9e817d997ff..6539516b776 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/contextmenu/CaseChangeMenu.java +++ b/src/main/java/org/jabref/gui/fieldeditors/contextmenu/CaseChangeMenu.java @@ -1,5 +1,7 @@ package org.jabref.gui.fieldeditors.contextmenu; +import java.util.ArrayList; +import java.util.List; import java.util.Objects; import javafx.beans.property.StringProperty; @@ -8,7 +10,9 @@ import javafx.scene.control.Menu; import javafx.scene.control.Tooltip; +import org.jabref.Globals; import org.jabref.logic.formatter.Formatters; +import org.jabref.logic.formatter.casechanger.ProtectTermsFormatter; import org.jabref.logic.l10n.Localization; import org.jabref.model.cleanup.Formatter; @@ -19,7 +23,10 @@ public CaseChangeMenu(final StringProperty text) { Objects.requireNonNull(text); // create menu items, one for each case changer - for (final Formatter caseChanger : Formatters.CASE_CHANGERS) { + List caseChangers = new ArrayList<>(); + caseChangers.addAll(Formatters.getCaseChangers()); + caseChangers.add(new ProtectTermsFormatter(Globals.protectedTermsLoader)); + for (final Formatter caseChanger : caseChangers) { CustomMenuItem menuItem = new CustomMenuItem(new Label(caseChanger.getName())); Tooltip toolTip = new Tooltip(caseChanger.getDescription()); Tooltip.install(menuItem.getContent(), toolTip); diff --git a/src/main/java/org/jabref/gui/fieldeditors/contextmenu/ConversionMenu.java b/src/main/java/org/jabref/gui/fieldeditors/contextmenu/ConversionMenu.java index 45b88b1b047..1bf5a1cd5ed 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/contextmenu/ConversionMenu.java +++ b/src/main/java/org/jabref/gui/fieldeditors/contextmenu/ConversionMenu.java @@ -19,7 +19,7 @@ public ConversionMenu(StringProperty text) { super(Localization.lang("Convert")); // create menu items, one for each converter - for (Formatter converter : Formatters.CONVERTERS) { + for (Formatter converter : Formatters.getConverters()) { CustomMenuItem menuItem = new CustomMenuItem(new Label(converter.getName())); Tooltip toolTip = new Tooltip(converter.getDescription()); Tooltip.install(menuItem.getContent(), toolTip); diff --git a/src/main/java/org/jabref/gui/fieldeditors/contextmenu/ProtectedTermsMenu.java b/src/main/java/org/jabref/gui/fieldeditors/contextmenu/ProtectedTermsMenu.java index d06ce5b8003..33a09471a67 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/contextmenu/ProtectedTermsMenu.java +++ b/src/main/java/org/jabref/gui/fieldeditors/contextmenu/ProtectedTermsMenu.java @@ -1,5 +1,8 @@ package org.jabref.gui.fieldeditors.contextmenu; +import java.util.List; +import java.util.stream.Collectors; + import javax.swing.SwingUtilities; import javafx.scene.control.Menu; @@ -13,10 +16,12 @@ import org.jabref.logic.formatter.casechanger.ProtectTermsFormatter; import org.jabref.logic.l10n.Localization; import org.jabref.logic.protectedterms.ProtectedTermsList; +import org.jabref.logic.protectedterms.ProtectedTermsLoader; +import org.jabref.model.cleanup.Formatter; class ProtectedTermsMenu extends Menu { - private static final ProtectTermsFormatter FORMATTER = new ProtectTermsFormatter(Globals.protectedTermsLoader); + private static final Formatter FORMATTER = new ProtectTermsFormatter(Globals.protectedTermsLoader); private final Menu externalFiles; private final TextArea opener; @@ -45,30 +50,32 @@ public ProtectedTermsMenu(TextArea opener) { private void updateFiles() { externalFiles.getItems().clear(); - for (ProtectedTermsList list : Globals.protectedTermsLoader.getProtectedTermsLists()) { - if (!list.isInternalList()) { - MenuItem fileItem = new MenuItem(list.getDescription()); - fileItem.setOnAction(event -> { - String selectedText = opener.getSelectedText(); - if ((selectedText != null) && !selectedText.isEmpty()) { - list.addProtectedTerm(selectedText); - } - }); - externalFiles.getItems().add(fileItem); - } + ProtectedTermsLoader loader = Globals.protectedTermsLoader; + List nonInternal = loader.getProtectedTermsLists().stream() + .filter(list -> !list.isInternalList()) + .collect(Collectors.toList()); + for (ProtectedTermsList list : nonInternal) { + MenuItem fileItem = new MenuItem(list.getDescription()); + fileItem.setOnAction(event -> { + String selectedText = opener.getSelectedText(); + if ((selectedText != null) && !selectedText.isEmpty()) { + list.addProtectedTerm(selectedText); + } + }); + externalFiles.getItems().add(fileItem); } externalFiles.getItems().add(new SeparatorMenuItem()); MenuItem addToNewFileItem = new MenuItem(Localization.lang("New") + "..."); addToNewFileItem.setOnAction(event -> { NewProtectedTermsFileDialog dialog = new NewProtectedTermsFileDialog(JabRefGUI.getMainFrame(), - Globals.protectedTermsLoader); + loader); SwingUtilities.invokeLater(() -> { dialog.setVisible(true); if (dialog.isOKPressed()) { // Update preferences with new list - Globals.prefs.setProtectedTermsPreferences(Globals.protectedTermsLoader); + Globals.prefs.setProtectedTermsPreferences(loader); this.updateFiles(); } }); diff --git a/src/main/java/org/jabref/gui/importer/fetcher/ACMPortalFetcher.java b/src/main/java/org/jabref/gui/importer/fetcher/ACMPortalFetcher.java index 067a348e5ef..50d034355aa 100644 --- a/src/main/java/org/jabref/gui/importer/fetcher/ACMPortalFetcher.java +++ b/src/main/java/org/jabref/gui/importer/fetcher/ACMPortalFetcher.java @@ -37,7 +37,7 @@ import org.jabref.logic.importer.fileformat.BibtexParser; import org.jabref.logic.l10n.Localization; import org.jabref.logic.net.URLDownload; -import org.jabref.logic.protectedterms.ProtectedTermsLoader; +import org.jabref.model.cleanup.Formatter; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.FieldName; import org.jabref.preferences.JabRefPreferences; @@ -87,8 +87,7 @@ public class ACMPortalFetcher implements PreviewEntryFetcher { private final HtmlToLatexFormatter htmlToLatexFormatter = new HtmlToLatexFormatter(); - private final ProtectTermsFormatter protectTermsFormatter = new ProtectTermsFormatter( - new ProtectedTermsLoader(Globals.prefs.getProtectedTermsPreferences())); + private final Formatter protectTermsFormatter = new ProtectTermsFormatter(Globals.protectedTermsLoader); private final UnitsToLatexFormatter unitsToLatexFormatter = new UnitsToLatexFormatter(); private String terms; diff --git a/src/main/java/org/jabref/gui/importer/fetcher/IEEEXploreFetcher.java b/src/main/java/org/jabref/gui/importer/fetcher/IEEEXploreFetcher.java index 3879ccb9e51..bcdda51fe65 100644 --- a/src/main/java/org/jabref/gui/importer/fetcher/IEEEXploreFetcher.java +++ b/src/main/java/org/jabref/gui/importer/fetcher/IEEEXploreFetcher.java @@ -32,6 +32,7 @@ import org.jabref.logic.journals.JournalAbbreviationPreferences; import org.jabref.logic.l10n.Localization; import org.jabref.logic.net.URLDownload; +import org.jabref.model.cleanup.Formatter; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.FieldName; import org.jabref.preferences.JabRefPreferences; @@ -64,7 +65,7 @@ public class IEEEXploreFetcher implements EntryFetcher { private static final Pattern SUPER_DETECTION_2 = Pattern.compile("\\(sup\\)([^(]+)\\(/sup\\)"); private static final String SUPER_TEXT_RESULT = "\\\\textsuperscript\\{$1\\}"; - private final ProtectTermsFormatter protectTermsFormatter = new ProtectTermsFormatter(); + private final Formatter protectTermsFormatter = new ProtectTermsFormatter(Globals.protectedTermsLoader); private final UnitsToLatexFormatter unitsToLatexFormatter = new UnitsToLatexFormatter(); private final HtmlToLatexFormatter htmlToLatexFormatter = new HtmlToLatexFormatter(); private final JCheckBox absCheckBox = new JCheckBox(Localization.lang("Include abstracts"), false); diff --git a/src/main/java/org/jabref/gui/protectedterms/ProtectedTermsDialog.java b/src/main/java/org/jabref/gui/protectedterms/ProtectedTermsDialog.java index 4556e8ec448..07a4f7739f1 100644 --- a/src/main/java/org/jabref/gui/protectedterms/ProtectedTermsDialog.java +++ b/src/main/java/org/jabref/gui/protectedterms/ProtectedTermsDialog.java @@ -90,10 +90,10 @@ public class ProtectedTermsDialog { private boolean okPressed; private final ProtectedTermsLoader loader; - public ProtectedTermsDialog(JabRefFrame frame, ProtectedTermsLoader loader) { + public ProtectedTermsDialog(JabRefFrame frame) { this.frame = Objects.requireNonNull(frame); - this.loader = Objects.requireNonNull(loader); + this.loader = Globals.protectedTermsLoader; init(); } diff --git a/src/main/java/org/jabref/logic/cleanup/Cleanups.java b/src/main/java/org/jabref/logic/cleanup/Cleanups.java index 226e3406466..6cfbe895ac9 100644 --- a/src/main/java/org/jabref/logic/cleanup/Cleanups.java +++ b/src/main/java/org/jabref/logic/cleanup/Cleanups.java @@ -1,7 +1,6 @@ package org.jabref.logic.cleanup; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import org.jabref.logic.formatter.Formatters; @@ -26,12 +25,8 @@ public class Cleanups { public static final FieldFormatterCleanups DEFAULT_SAVE_ACTIONS; public static final FieldFormatterCleanups RECOMMEND_BIBTEX_ACTIONS; public static final FieldFormatterCleanups RECOMMEND_BIBLATEX_ACTIONS; - public static List availableFormatters; static { - availableFormatters = new ArrayList<>(); - availableFormatters.addAll(Formatters.ALL); - List defaultFormatters = new ArrayList<>(); defaultFormatters.add(new FieldFormatterCleanup(FieldName.PAGES, new NormalizePagesFormatter())); defaultFormatters.add(new FieldFormatterCleanup(FieldName.DATE, new NormalizeDateFormatter())); @@ -60,8 +55,8 @@ public class Cleanups { private Cleanups() { } - public static List getAvailableFormatters() { - return Collections.unmodifiableList(availableFormatters); + public static List getBuiltInFormatters() { + return Formatters.getAll(); } public static List parse(String formatterString) { @@ -130,7 +125,7 @@ public static FieldFormatterCleanups parse(List formatterMetaList) { } private static Formatter getFormatterFromString(String formatterName) { - for (Formatter formatter : availableFormatters) { + for (Formatter formatter : getBuiltInFormatters()) { if (formatterName.equals(formatter.getKey())) { return formatter; } diff --git a/src/main/java/org/jabref/logic/formatter/Formatters.java b/src/main/java/org/jabref/logic/formatter/Formatters.java index 9f682ae5130..b4930aabe6f 100644 --- a/src/main/java/org/jabref/logic/formatter/Formatters.java +++ b/src/main/java/org/jabref/logic/formatter/Formatters.java @@ -22,7 +22,6 @@ import org.jabref.logic.formatter.bibtexfields.UnitsToLatexFormatter; import org.jabref.logic.formatter.casechanger.CapitalizeFormatter; import org.jabref.logic.formatter.casechanger.LowerCaseFormatter; -import org.jabref.logic.formatter.casechanger.ProtectTermsFormatter; import org.jabref.logic.formatter.casechanger.SentenceCaseFormatter; import org.jabref.logic.formatter.casechanger.TitleCaseFormatter; import org.jabref.logic.formatter.casechanger.UpperCaseFormatter; @@ -32,23 +31,22 @@ public class Formatters { - public static final List CONVERTERS = Arrays.asList( + private static final List CONVERTERS = Arrays.asList( new HtmlToLatexFormatter(), new HtmlToUnicodeFormatter(), new LatexToUnicodeFormatter(), new UnicodeToLatexFormatter() ); - public static final List CASE_CHANGERS = Arrays.asList( + private static final List CASE_CHANGERS = Arrays.asList( new CapitalizeFormatter(), new LowerCaseFormatter(), - new ProtectTermsFormatter(), new SentenceCaseFormatter(), new TitleCaseFormatter(), new UpperCaseFormatter() ); - public static final List OTHERS = Arrays.asList( + private static final List OTHERS = Arrays.asList( new ClearFormatter(), new LatexCleanupFormatter(), new MinifyNameListFormatter(), @@ -63,8 +61,6 @@ public class Formatters { new EscapeUnderscoresFormatter() ); - public static final List ALL = new ArrayList<>(); - private static final String REGEX = "regex"; private static final int LENGTH_OF_REGEX_PREFIX = REGEX.length(); @@ -72,16 +68,43 @@ public class Formatters { private Formatters() { } + public static final List getConverters() { + List converters = new ArrayList<>(); + converters.addAll(CONVERTERS); + return converters; + } + + public static final List getCaseChangers() { + List caseChangers = new ArrayList<>(); + caseChangers.addAll(CASE_CHANGERS); + return caseChangers; + } + + public static final List getOthers() { + List others = new ArrayList<>(); + others.addAll(OTHERS); + return others; + } + + public static final List getAll() { + List all = new ArrayList<>(); + all.addAll(CONVERTERS); + all.addAll(CASE_CHANGERS); + all.addAll(OTHERS); + return all; + } + public static Optional getFormatterForModifier(String modifier) { Objects.requireNonNull(modifier); Optional formatter; + List all = getAll(); if (modifier.matches("regex.*")) { String regex = modifier.substring(LENGTH_OF_REGEX_PREFIX); RegexFormatter.setRegex(regex); - formatter = ALL.stream().filter(f -> f.getKey().equals("regex")).findAny(); + formatter = all.stream().filter(f -> f.getKey().equals("regex")).findAny(); } else { - formatter = ALL.stream().filter(f -> f.getKey().equals(modifier)).findAny(); + formatter = all.stream().filter(f -> f.getKey().equals(modifier)).findAny(); } if (formatter.isPresent()) { return formatter; @@ -96,9 +119,4 @@ public static Optional getFormatterForModifier(String modifier) { } } - static { - ALL.addAll(CONVERTERS); - ALL.addAll(CASE_CHANGERS); - ALL.addAll(OTHERS); - } } diff --git a/src/main/java/org/jabref/logic/formatter/casechanger/ProtectTermsFormatter.java b/src/main/java/org/jabref/logic/formatter/casechanger/ProtectTermsFormatter.java index 0933277cf1f..60109ca321a 100644 --- a/src/main/java/org/jabref/logic/formatter/casechanger/ProtectTermsFormatter.java +++ b/src/main/java/org/jabref/logic/formatter/casechanger/ProtectTermsFormatter.java @@ -10,27 +10,10 @@ public class ProtectTermsFormatter implements Formatter { - private static ProtectedTermsLoader protectedTermsLoader; - - /** - * @Deprecated use ProtectTermsFormatter(ProtectedTermsLoader) instead - */ - @Deprecated - public ProtectTermsFormatter() { - } + private final ProtectedTermsLoader protectedTermsLoader; public ProtectTermsFormatter(ProtectedTermsLoader protectedTermsLoader) { - ProtectTermsFormatter.protectedTermsLoader = protectedTermsLoader; - } - - /** - * This must be called from JabRefMain - * - * @deprecated use ProtectTermsFormatter(ProtectedTermsLoader) instead - */ - @Deprecated - public static void setProtectedTermsLoader(ProtectedTermsLoader loader) { - protectedTermsLoader = loader; + this.protectedTermsLoader = protectedTermsLoader; } private String format(String text, List listOfWords) { @@ -50,8 +33,7 @@ public String format(String text) { if (text.isEmpty()) { return text; } - Objects.requireNonNull(ProtectTermsFormatter.protectedTermsLoader); - return this.format(text, ProtectTermsFormatter.protectedTermsLoader.getProtectedTerms()); + return this.format(text, this.protectedTermsLoader.getProtectedTerms()); } @Override diff --git a/src/main/java/org/jabref/logic/protectedterms/ProtectedTermsLoader.java b/src/main/java/org/jabref/logic/protectedterms/ProtectedTermsLoader.java index 165489a2ef6..d64c4a013ac 100644 --- a/src/main/java/org/jabref/logic/protectedterms/ProtectedTermsLoader.java +++ b/src/main/java/org/jabref/logic/protectedterms/ProtectedTermsLoader.java @@ -3,7 +3,6 @@ import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; -import java.nio.charset.Charset; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; @@ -144,14 +143,6 @@ public static ProtectedTermsList readProtectedTermsListFromFile(File file, boole return parser.getProtectTermsList(enabled, false); } - public static ProtectedTermsList readProtectedTermsListFromFile(File file, Charset encoding, boolean enabled) - throws FileNotFoundException { - LOGGER.debug("Reading term list from file " + file); - ProtectedTermsParser parser = new ProtectedTermsParser(); - parser.readTermsFromFile(Objects.requireNonNull(file), Objects.requireNonNull(encoding)); - return parser.getProtectTermsList(enabled, false); - } - public boolean removeProtectedTermsList(ProtectedTermsList termList) { termList.setEnabled(false); return mainList.remove(termList); diff --git a/src/test/java/org/jabref/logic/formatter/FormatterTest.java b/src/test/java/org/jabref/logic/formatter/FormatterTest.java index ab811a2ecdb..404759a64e4 100644 --- a/src/test/java/org/jabref/logic/formatter/FormatterTest.java +++ b/src/test/java/org/jabref/logic/formatter/FormatterTest.java @@ -40,8 +40,6 @@ public class FormatterTest { - - private static ProtectedTermsLoader protectedTermsLoader; @BeforeAll diff --git a/src/test/java/org/jabref/logic/formatter/casechanger/ProtectTermsFormatterTest.java b/src/test/java/org/jabref/logic/formatter/casechanger/ProtectTermsFormatterTest.java index c6fcb1fafd7..a21eb71c99c 100644 --- a/src/test/java/org/jabref/logic/formatter/casechanger/ProtectTermsFormatterTest.java +++ b/src/test/java/org/jabref/logic/formatter/casechanger/ProtectTermsFormatterTest.java @@ -19,11 +19,9 @@ public class ProtectTermsFormatterTest { @BeforeEach public void setUp() { - ProtectTermsFormatter - .setProtectedTermsLoader( + formatter = new ProtectTermsFormatter( new ProtectedTermsLoader(new ProtectedTermsPreferences(ProtectedTermsLoader.getInternalLists(), Collections.emptyList(), Collections.emptyList(), Collections.emptyList()))); - formatter = new ProtectTermsFormatter(); } @Test From 36e4f0e56ecc0fd5653b5bfbed15eecf34e38f47 Mon Sep 17 00:00:00 2001 From: Brainsucker92 Date: Thu, 15 Feb 2018 18:00:03 +0100 Subject: [PATCH 42/94] [WIP] Fix for issue 2831 (#3721) * Added executeAndReturn method * Abbreviations should run parallel now. * Added logging message * Null check is now done by Objects.requireNonNull(...) Added method executeAll * executeAll method now returns a list of all Future objects * Removed empty lines, changed log message status to info instead of debug * Some more empty lines had to die. >:( * Removed throw of InterruptedException * Callables are now invoked by the executeAll method. * executeAll will now return an empty list instead of null * Replaced for-loop by using a stream instead. * Exceptions are now logged as errors * Replaced null check with Objects.requireNonNull(... * Added JavaDoc comment, fixed typo, returning empty list in catch block * Fixed variable declaration order * Renamed `executeAndReturn` method to `execute` * Separated Logger import * Added change log message for issue 2831 * Added bib file generator as python script * Removed empty lines to satisfy code check --- CHANGELOG.md | 1 + scripts/bib-file-generator.py | 15 +++++ .../org/jabref/JabRefExecutorService.java | 63 ++++++++++++------- .../jabref/gui/journals/AbbreviateAction.java | 30 ++++++--- 4 files changed, 80 insertions(+), 29 deletions(-) create mode 100644 scripts/bib-file-generator.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 636d3041886..f61d58404a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ We refer to [GitHub issues](https://github.com/JabRef/jabref/issues) by using `# ## [Unreleased] ### Changed +- Abbreviate journal names functionality is now running parallel, increasing performance significantly. [#2831] (https://github.com/JabRef/jabref/issues/2831) - Changed ID-based entry generator to store the last used fetcher. [#2796] (https://github.com/JabRef/jabref/issues/2796) - Reorganised annotation information on the right side of the "File annotations" tab. [#3109](https://github.com/JabRef/jabref/issues/3109) - We now show a small notification icon in the entry editor when we detect data inconsistency or other problems. [#3145](https://github.com/JabRef/jabref/issues/3145) diff --git a/scripts/bib-file-generator.py b/scripts/bib-file-generator.py new file mode 100644 index 00000000000..1236661394c --- /dev/null +++ b/scripts/bib-file-generator.py @@ -0,0 +1,15 @@ +number_of_entries = 100000 +file = open("generatedDatabase.bib", 'w') + +for i in range(number_of_entries): + entry = """@article{%i, + author = {%i}, + title = {%i}, + journal = {%i}, + volume = {%i}, + year = {%i}, + pages = {%i}, + }""" % (i, i, i, i, i, i, i) + file.write(entry) +file.flush() +file.close() \ No newline at end of file diff --git a/src/main/java/org/jabref/JabRefExecutorService.java b/src/main/java/org/jabref/JabRefExecutorService.java index c3f3d9854e8..b9c4886c257 100644 --- a/src/main/java/org/jabref/JabRefExecutorService.java +++ b/src/main/java/org/jabref/JabRefExecutorService.java @@ -1,5 +1,10 @@ package org.jabref; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Objects; import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.Callable; @@ -12,7 +17,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; - /** * Responsible for managing of all threads (except Swing threads) in JabRef */ @@ -36,24 +40,17 @@ public class JabRefExecutorService implements Executor { private final Timer timer = new Timer("timer", true); private Thread remoteThread; - private JabRefExecutorService() { } + private JabRefExecutorService() { + } @Override public void execute(Runnable command) { - if (command == null) { - LOGGER.debug("Received null as command for execution"); - return; - } - + Objects.requireNonNull(command); executorService.execute(command); } public void executeAndWait(Runnable command) { - if (command == null) { - LOGGER.debug("Received null as command for execution"); - return; - } - + Objects.requireNonNull(command); Future future = executorService.submit(command); while (true) { try { @@ -67,12 +64,8 @@ public void executeAndWait(Runnable command) { } } - public boolean executeAndWait(Callable command) { - if (command == null) { - LOGGER.debug("Received null as command for execution"); - return false; - } - + public boolean executeAndWait(Callable command) { + Objects.requireNonNull(command); Future future = executorService.submit(command); while (true) { try { @@ -87,6 +80,35 @@ public boolean executeAndWait(Callable command) { } } + /** + * Executes a callable task that provides a return value after the calculation is done. + * + * @param command The task to execute. + * @return A Future object that provides the returning value. + */ + public Future execute(Callable command) { + Objects.requireNonNull(command); + return executorService.submit(command); + } + + /** + * Executes a collection of callable tasks and returns a List of the resulting Future objects after the calculation is done. + * + * @param tasks The tasks to execute + * @return A List of Future objects that provide the returning values. + */ + public List> executeAll(Collection> tasks) { + Objects.requireNonNull(tasks); + List> futures = new ArrayList<>(); + try { + futures = executorService.invokeAll(tasks); + } catch (InterruptedException exception) { + LOGGER.error("Unable to execute tasks", exception); + return Collections.emptyList(); + } + return futures; + } + public void executeInterruptableTask(final Runnable runnable) { this.lowPriorityExecutorService.execute(runnable); } @@ -96,10 +118,7 @@ public void executeInterruptableTask(final Runnable runnable, String taskName) { } public void executeInterruptableTaskAndWait(Runnable runnable) { - if (runnable == null) { - LOGGER.debug("Received null as command for execution"); - return; - } + Objects.requireNonNull(runnable); Future future = lowPriorityExecutorService.submit(runnable); while (true) { diff --git a/src/main/java/org/jabref/gui/journals/AbbreviateAction.java b/src/main/java/org/jabref/gui/journals/AbbreviateAction.java index 94798723075..8663090cde0 100644 --- a/src/main/java/org/jabref/gui/journals/AbbreviateAction.java +++ b/src/main/java/org/jabref/gui/journals/AbbreviateAction.java @@ -1,7 +1,11 @@ package org.jabref.gui.journals; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; import org.jabref.Globals; import org.jabref.JabRefExecutorService; @@ -12,12 +16,16 @@ import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.InternalBibtexFields; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * Converts journal full names to either iso or medline abbreviations for all * selected entries. */ public class AbbreviateAction extends AbstractWorker { + private static final Logger LOGGER = LoggerFactory.getLogger(AbbreviateAction.class); private final BasePanel panel; private String message = ""; private final boolean iso; @@ -35,14 +43,14 @@ public void init() { @Override public void run() { List entries = panel.getSelectedEntries(); - UndoableAbbreviator undoableAbbreviator = new UndoableAbbreviator( Globals.journalAbbreviationLoader.getRepository(Globals.prefs.getJournalAbbreviationPreferences()), iso); NamedCompound ce = new NamedCompound(Localization.lang("Abbreviate journal names")); - int count = 0; + Set> tasks = new HashSet<>(); + // Collect all callables to execute in one collection. for (BibEntry entry : entries) { Callable callable = () -> { for (String journalField : InternalBibtexFields.getJournalNameFields()) { @@ -50,15 +58,23 @@ public void run() { return true; } } - return false; }; + tasks.add(callable); + } - boolean result = JabRefExecutorService.INSTANCE.executeAndWait(callable); - if (result) { - count++; + // Execute the callables and wait for the results. + List> futures = JabRefExecutorService.INSTANCE.executeAll(tasks); + + // Evaluate the results of the callables. + long count = futures.stream().filter(future -> { + try { + return future.get(); + } catch (InterruptedException | ExecutionException exception) { + LOGGER.error("Unable to retrieve value.", exception); + return false; } - } + }).count(); if (count > 0) { ce.end(); From b3c6f0a54a083351331bbbb41455989f77412c0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Lenhard?= Date: Fri, 16 Feb 2018 15:56:36 +0100 Subject: [PATCH 43/94] Improve performance for managing journal abbreviations (#3729) * Remove unnecessary abbreviation parsing * Only write journal lists if entries have been changed * Remove unnecessary log statement * Always write the list of external files --- CHANGELOG.md | 1 + .../journals/ManageJournalAbbreviationsViewModel.java | 10 +++++++++- .../logic/journals/JournalAbbreviationRepository.java | 6 ++---- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f61d58404a8..5f6799a48c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,7 @@ The new default removes the linked file from the entry instead of deleting the f - We added a new cleanup operation that replaces ligatures with their expanded form. [#3613](https://github.com/JabRef/jabref/issues/3613) ### Fixed +- We fixed several performance problems with the management of journal abbreviations [#3323](https://github.com/JabRef/jabref/issues/3323) - We fixed an issue where changing the type of an entry did not update the label in the tool bar of the entry editor and the contents of the currently visible entry editor tab - We fixed an issue where pressing space caused the cursor to jump to the start of the text field. [#3471](https://github.com/JabRef/jabref/issues/3471) - We fixed the missing dot in the name of an exported file. [#3576](https://github.com/JabRef/jabref/issues/3576) diff --git a/src/main/java/org/jabref/gui/journals/ManageJournalAbbreviationsViewModel.java b/src/main/java/org/jabref/gui/journals/ManageJournalAbbreviationsViewModel.java index 78c347ceb6a..f1c031a4492 100644 --- a/src/main/java/org/jabref/gui/journals/ManageJournalAbbreviationsViewModel.java +++ b/src/main/java/org/jabref/gui/journals/ManageJournalAbbreviationsViewModel.java @@ -54,6 +54,7 @@ public class ManageJournalAbbreviationsViewModel extends AbstractViewModel { private final TaskExecutor taskExecutor; private final JournalAbbreviationPreferences abbreviationsPreferences; private final JournalAbbreviationLoader journalAbbreviationLoader; + private boolean shouldWriteLists = false; public ManageJournalAbbreviationsViewModel(PreferencesService preferences, DialogService dialogService, TaskExecutor taskExecutor, JournalAbbreviationLoader journalAbbreviationLoader) { this.preferences = Objects.requireNonNull(preferences); @@ -234,6 +235,7 @@ public void addAbbreviation(String name, String abbreviation) { } else { abbreviations.add(abbreviationViewModel); currentAbbreviation.set(abbreviationViewModel); + shouldWriteLists = true; } } @@ -274,6 +276,7 @@ private void setCurrentAbbreviationNameAndAbbreviationIfValid(String name, Strin } currentAbbreviation.get().setName(name); currentAbbreviation.get().setAbbreviation(abbreviation); + shouldWriteLists = true; } /** @@ -294,6 +297,7 @@ public void deleteAbbreviation() { currentAbbreviation.set(null); } abbreviations.remove(index); + shouldWriteLists = true; } } } @@ -347,7 +351,11 @@ public void selectLastJournalFile() { */ public void saveEverythingAndUpdateAutoCompleter() { saveExternalFilesList(); - saveJournalAbbreviationFiles(); + + if (shouldWriteLists) { + saveJournalAbbreviationFiles(); + shouldWriteLists = false; + } // Update journal abbreviation loader journalAbbreviationLoader.update(abbreviationsPreferences); diff --git a/src/main/java/org/jabref/logic/journals/JournalAbbreviationRepository.java b/src/main/java/org/jabref/logic/journals/JournalAbbreviationRepository.java index a3692c9817d..305bb340aa6 100644 --- a/src/main/java/org/jabref/logic/journals/JournalAbbreviationRepository.java +++ b/src/main/java/org/jabref/logic/journals/JournalAbbreviationRepository.java @@ -60,11 +60,9 @@ public Optional getAbbreviation(String journalName) { public void addEntry(Abbreviation abbreviation) { Objects.requireNonNull(abbreviation); + // Abbreviation equality is tested on name only, so we might have to remove an old abbreviation if (abbreviations.contains(abbreviation)) { - Abbreviation previous = getAbbreviation(abbreviation.getName()).get(); - abbreviations.remove(previous); - LOGGER.info("Duplicate journal abbreviation - old one will be overwritten by new one\nOLD: " - + previous + "\nNEW: " + abbreviation); + abbreviations.remove(abbreviation); } abbreviations.add(abbreviation); From bb2b078336b09df8707e02fc8464ffec1d8b2aaf Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Fri, 16 Feb 2018 16:05:18 +0100 Subject: [PATCH 44/94] Add EndNote XML importer (#3713) * Add EndNote XML importer * add some optionals of Nullable to fix parsing errors * Implement feedback * Fix a few other NPE * Improve importer according to feedback from user --- CHANGELOG.md | 1 + .../logic/importer/ImportFormatReader.java | 2 + .../fileformat/EndnoteXmlImporter.java | 306 ++++++++++++++++++ .../importer/fileformat/MedlineImporter.java | 35 +- .../java/org/jabref/logic/util/FileType.java | 5 +- src/main/resources/xjc/endnote/RSXML.dtd | 168 ++++++++++ .../fileformat/BibTeXMLImporterTestFiles.java | 2 +- .../BiblioscapeImporterTestFiles.java | 2 +- .../fileformat/CopacImporterTestFiles.java | 2 +- .../EndnoteXmlImporterTestFiles.java | 54 ++++ .../fileformat/ImporterTestEngine.java | 12 +- .../fileformat/MedlineImporterTestFiles.java | 2 +- .../PdfContentImporterTestFiles.java | 2 +- .../fileformat/RISImporterTestFiles.java | 2 +- .../fileformat/SilverPlatterImporterTest.java | 2 +- .../EndnoteXmlImporterTestArticle.bib | 16 + .../EndnoteXmlImporterTestArticle.xml | 131 ++++++++ .../EndnoteXmlImporterTestArticle2.bib | 24 ++ .../EndnoteXmlImporterTestArticle2.xml | 184 +++++++++++ xjc.gradle | 6 + 20 files changed, 935 insertions(+), 23 deletions(-) create mode 100644 src/main/java/org/jabref/logic/importer/fileformat/EndnoteXmlImporter.java create mode 100644 src/main/resources/xjc/endnote/RSXML.dtd create mode 100644 src/test/java/org/jabref/logic/importer/fileformat/EndnoteXmlImporterTestFiles.java create mode 100644 src/test/resources/org/jabref/logic/importer/fileformat/EndnoteXmlImporterTestArticle.bib create mode 100644 src/test/resources/org/jabref/logic/importer/fileformat/EndnoteXmlImporterTestArticle.xml create mode 100644 src/test/resources/org/jabref/logic/importer/fileformat/EndnoteXmlImporterTestArticle2.bib create mode 100644 src/test/resources/org/jabref/logic/importer/fileformat/EndnoteXmlImporterTestArticle2.xml diff --git a/CHANGELOG.md b/CHANGELOG.md index 5f6799a48c7..e7e82319c73 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ We refer to [GitHub issues](https://github.com/JabRef/jabref/issues) by using `# - We added [oaDOI](https://oadoi.org/) as a fulltext provider, so that JabRef is now able to provide fulltexts for more than 90 million open-access articles. - We changed one default of [Cleanup entries dialog](http://help.jabref.org/en/CleanupEntries): Per default, the PDF are not moved to the default file directory anymore. [#3619](https://github.com/JabRef/jabref/issues/3619) - We added a new type of group that shows all items referenced in a given LaTeX file (actually the generated AUX file). [#1664](https://github.com/JabRef/jabref/issues/1664) +- We added an importer for the EndNote XML format. [Feature request in the forum](http://discourse.jabref.org/t/import-from-bookends-or-endnote/1048) - We added the export of the `translator` field to the according MS-Office XML field. [#1750, comment](https://github.com/JabRef/jabref/issues/1750#issuecomment-357350986) - We changed the import of the MS-Office XML fields `bookauthor` and `translator`. Both are now imported to their corresponding bibtex/biblatex fields. - We improved the export of the `address` and `location` field to the MS-Office XML fields. If the address field does not contain a comma, it is treated as single value and exported to the field `city`. [#1750, comment](https://github.com/JabRef/jabref/issues/1750#issuecomment-357539167) diff --git a/src/main/java/org/jabref/logic/importer/ImportFormatReader.java b/src/main/java/org/jabref/logic/importer/ImportFormatReader.java index 6e7c31415b8..f3d5b9908d5 100644 --- a/src/main/java/org/jabref/logic/importer/ImportFormatReader.java +++ b/src/main/java/org/jabref/logic/importer/ImportFormatReader.java @@ -14,6 +14,7 @@ import org.jabref.logic.importer.fileformat.CopacImporter; import org.jabref.logic.importer.fileformat.CustomImporter; import org.jabref.logic.importer.fileformat.EndnoteImporter; +import org.jabref.logic.importer.fileformat.EndnoteXmlImporter; import org.jabref.logic.importer.fileformat.FreeCiteImporter; import org.jabref.logic.importer.fileformat.InspecImporter; import org.jabref.logic.importer.fileformat.IsiImporter; @@ -56,6 +57,7 @@ public void resetImportFormats(ImportFormatPreferences newImportFormatPreference formats.add(new BibTeXMLImporter()); formats.add(new CopacImporter()); formats.add(new EndnoteImporter(importFormatPreferences)); + formats.add(new EndnoteXmlImporter(importFormatPreferences)); formats.add(new FreeCiteImporter(importFormatPreferences)); formats.add(new InspecImporter()); formats.add(new IsiImporter()); diff --git a/src/main/java/org/jabref/logic/importer/fileformat/EndnoteXmlImporter.java b/src/main/java/org/jabref/logic/importer/fileformat/EndnoteXmlImporter.java new file mode 100644 index 00000000000..34a600321cb --- /dev/null +++ b/src/main/java/org/jabref/logic/importer/fileformat/EndnoteXmlImporter.java @@ -0,0 +1,306 @@ +package org.jabref.logic.importer.fileformat; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.util.Collections; +import java.util.List; +import java.util.Locale; +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Collectors; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Unmarshaller; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import org.jabref.logic.importer.ImportFormatPreferences; +import org.jabref.logic.importer.Importer; +import org.jabref.logic.importer.ParseException; +import org.jabref.logic.importer.Parser; +import org.jabref.logic.importer.ParserResult; +import org.jabref.logic.importer.fileformat.endnote.Abstract; +import org.jabref.logic.importer.fileformat.endnote.Authors; +import org.jabref.logic.importer.fileformat.endnote.Contributors; +import org.jabref.logic.importer.fileformat.endnote.Dates; +import org.jabref.logic.importer.fileformat.endnote.ElectronicResourceNum; +import org.jabref.logic.importer.fileformat.endnote.Isbn; +import org.jabref.logic.importer.fileformat.endnote.Keywords; +import org.jabref.logic.importer.fileformat.endnote.Notes; +import org.jabref.logic.importer.fileformat.endnote.Number; +import org.jabref.logic.importer.fileformat.endnote.Pages; +import org.jabref.logic.importer.fileformat.endnote.PdfUrls; +import org.jabref.logic.importer.fileformat.endnote.Record; +import org.jabref.logic.importer.fileformat.endnote.RefType; +import org.jabref.logic.importer.fileformat.endnote.RelatedUrls; +import org.jabref.logic.importer.fileformat.endnote.SecondaryTitle; +import org.jabref.logic.importer.fileformat.endnote.Style; +import org.jabref.logic.importer.fileformat.endnote.Title; +import org.jabref.logic.importer.fileformat.endnote.Titles; +import org.jabref.logic.importer.fileformat.endnote.Url; +import org.jabref.logic.importer.fileformat.endnote.Urls; +import org.jabref.logic.importer.fileformat.endnote.Volume; +import org.jabref.logic.importer.fileformat.endnote.Xml; +import org.jabref.logic.importer.fileformat.endnote.Year; +import org.jabref.logic.util.FileType; +import org.jabref.model.entry.BibEntry; +import org.jabref.model.entry.BiblatexEntryType; +import org.jabref.model.entry.BiblatexEntryTypes; +import org.jabref.model.entry.FieldName; +import org.jabref.model.entry.LinkedFile; +import org.jabref.model.strings.StringUtil; +import org.jabref.model.util.OptionalUtil; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Importer for the Endnote XML format. + * + * Based on dtd scheme downloaded from Article #122577 in http://kbportal.thomson.com. + */ +public class EndnoteXmlImporter extends Importer implements Parser { + + private static final Logger LOGGER = LoggerFactory.getLogger(EndnoteXmlImporter.class); + private final ImportFormatPreferences preferences; + private Unmarshaller unmarshaller; + + public EndnoteXmlImporter(ImportFormatPreferences preferences) { + this.preferences = preferences; + } + + @Override + public String getName() { + return "EndNote XML"; + } + + @Override + public FileType getFileType() { + return FileType.ENDNOTE_XML; + } + + @Override + public String getId() { + return "endnote"; + } + + @Override + public String getDescription() { + return "Importer for the EndNote XML format."; + } + + @Override + public boolean isRecognizedFormat(BufferedReader reader) throws IOException { + String str; + int i = 0; + while (((str = reader.readLine()) != null) && (i < 50)) { + if (str.toLowerCase(Locale.ENGLISH).contains("")) { + return true; + } + + i++; + } + return false; + } + + @Override + public ParserResult importDatabase(BufferedReader reader) throws IOException { + Objects.requireNonNull(reader); + + try { + Object unmarshalledObject = unmarshallRoot(reader); + + if (unmarshalledObject instanceof Xml) { + // Check whether we have an article set, an article, a book article or a book article set + Xml root = (Xml) unmarshalledObject; + List bibEntries = root.getRecords() + .getRecord() + .stream() + .map(this::parseRecord) + .collect(Collectors.toList()); + + return new ParserResult(bibEntries); + } else { + return ParserResult.fromErrorMessage("File does not start with xml tag."); + } + } catch (JAXBException | XMLStreamException e) { + LOGGER.debug("could not parse document", e); + return ParserResult.fromError(e); + } + } + + private Object unmarshallRoot(BufferedReader reader) throws XMLStreamException, JAXBException { + initUnmarshaller(); + + XMLInputFactory xmlInputFactory = XMLInputFactory.newFactory(); + XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(reader); + + // Go to the root element + while (!xmlStreamReader.isStartElement()) { + xmlStreamReader.next(); + } + + return unmarshaller.unmarshal(xmlStreamReader); + } + + private void initUnmarshaller() throws JAXBException { + if (unmarshaller == null) { + // Lazy init because this is expensive + JAXBContext context = JAXBContext.newInstance("org.jabref.logic.importer.fileformat.endnote"); + unmarshaller = context.createUnmarshaller(); + } + } + + private static BiblatexEntryType convertRefNameToType(String refName) { + switch (refName.toLowerCase().trim()) { + case "artwork": + return BiblatexEntryTypes.MISC; + case "generic": + return BiblatexEntryTypes.MISC; + case "electronic rticle": + return BiblatexEntryTypes.ELECTRONIC; + case "book section": + return BiblatexEntryTypes.INBOOK; + case "book": + return BiblatexEntryTypes.BOOK; + case "journal article": + return BiblatexEntryTypes.ARTICLE; + + default: + return BiblatexEntryTypes.ARTICLE; + } + } + + private BibEntry parseRecord(Record record) { + BibEntry entry = new BibEntry(); + + entry.setType(getType(record)); + Optional.ofNullable(getAuthors(record)) + .ifPresent(value -> entry.setField(FieldName.AUTHOR, value)); + Optional.ofNullable(record.getTitles()) + .map(Titles::getTitle) + .map(Title::getStyle) + .map(Style::getvalue) + .ifPresent(value -> entry.setField(FieldName.TITLE, clean(value))); + Optional.ofNullable(record.getTitles()) + .map(Titles::getSecondaryTitle) + .map(SecondaryTitle::getStyle) + .map(Style::getvalue) + .ifPresent(value -> entry.setField(FieldName.JOURNAL, clean(value))); + Optional.ofNullable(record.getPages()) + .map(Pages::getStyle) + .map(Style::getvalue) + .ifPresent(value -> entry.setField(FieldName.PAGES, value)); + Optional.ofNullable(record.getNumber()) + .map(Number::getStyle) + .map(Style::getvalue) + .ifPresent(value -> entry.setField(FieldName.NUMBER, value)); + Optional.ofNullable(record.getVolume()) + .map(Volume::getStyle) + .map(Style::getvalue) + .ifPresent(value -> entry.setField(FieldName.VOLUME, value)); + Optional.ofNullable(record.getDates()) + .map(Dates::getYear) + .map(Year::getStyle) + .map(Style::getvalue) + .ifPresent(value -> entry.setField(FieldName.YEAR, value)); + Optional.ofNullable(record.getNotes()) + .map(Notes::getStyle) + .map(Style::getvalue) + .ifPresent(value -> entry.setField(FieldName.NOTE, value.trim())); + getUrl(record) + .ifPresent(value -> entry.setField(FieldName.URL, value)); + entry.putKeywords(getKeywords(record), preferences.getKeywordSeparator()); + Optional.ofNullable(record.getAbstract()) + .map(Abstract::getStyle) + .map(Style::getvalue) + .ifPresent(value -> entry.setField(FieldName.ABSTRACT, value.trim())); + entry.setFiles(getLinkedFiles(record)); + Optional.ofNullable(record.getIsbn()) + .map(Isbn::getStyle) + .map(Style::getvalue) + .ifPresent(value -> entry.setField(FieldName.ISBN, clean(value))); + Optional.ofNullable(record.getElectronicResourceNum()) + .map(ElectronicResourceNum::getStyle) + .map(Style::getvalue) + .ifPresent(doi -> entry.setField(FieldName.DOI, doi.trim())); + + return entry; + } + + private BiblatexEntryType getType(Record record) { + return Optional.ofNullable(record.getRefType()) + .map(RefType::getName) + .map(EndnoteXmlImporter::convertRefNameToType) + .orElse(BiblatexEntryTypes.ARTICLE); + } + + private List getLinkedFiles(Record record) { + Optional urls = Optional.ofNullable(record.getUrls()) + .map(Urls::getPdfUrls); + return OptionalUtil.toStream(urls) + .flatMap(pdfUrls -> pdfUrls.getUrl().stream()) + .flatMap(url -> OptionalUtil.toStream(getUrlValue(url))) + .map(url -> new LinkedFile("", url, "PDF")) + .collect(Collectors.toList()); + } + + private Optional getUrl(Record record) { + Optional urls = Optional.ofNullable(record.getUrls()) + .map(Urls::getRelatedUrls); + return OptionalUtil.toStream(urls) + .flatMap(url -> url.getUrl().stream()) + .flatMap(url -> OptionalUtil.toStream(getUrlValue(url))) + .findFirst(); + } + + private Optional getUrlValue(Url url) { + return Optional.ofNullable(url) + .map(Url::getStyle) + .map(Style::getvalue) + .map(this::clean); + } + + private List getKeywords(Record record) { + Keywords keywords = record.getKeywords(); + if (keywords != null) { + return keywords.getKeyword() + .stream() + .map(keyword -> keyword.getStyle().getvalue()) + .collect(Collectors.toList()); + } else { + return Collections.emptyList(); + } + } + + private String getAuthors(Record record) { + Optional authors = Optional.ofNullable(record.getContributors()) + .map(Contributors::getAuthors); + return OptionalUtil.toStream(authors) + .flatMap(value -> value.getAuthor().stream()) + .map(author -> author.getStyle().getvalue()) + .collect(Collectors.joining(" and ")); + } + + private String clean(String input) { + return StringUtil.unifyLineBreaks(input, " ") + .trim() + .replaceAll(" +", " "); + } + + @Override + public List parseEntries(InputStream inputStream) throws ParseException { + try { + return importDatabase( + new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))).getDatabase().getEntries(); + } catch (IOException e) { + LOGGER.error(e.getLocalizedMessage(), e); + } + return Collections.emptyList(); + } +} diff --git a/src/main/java/org/jabref/logic/importer/fileformat/MedlineImporter.java b/src/main/java/org/jabref/logic/importer/fileformat/MedlineImporter.java index c9044ba46ac..b2b362a27da 100644 --- a/src/main/java/org/jabref/logic/importer/fileformat/MedlineImporter.java +++ b/src/main/java/org/jabref/logic/importer/fileformat/MedlineImporter.java @@ -93,6 +93,7 @@ public class MedlineImporter extends Importer implements Parser { private static final String KEYWORD_SEPARATOR = "; "; private static final Locale ENGLISH = Locale.ENGLISH; + private Unmarshaller unmarshaller; private static String join(List list, String string) { return Joiner.on(string).join(list); @@ -141,17 +142,7 @@ public ParserResult importDatabase(BufferedReader reader) throws IOException { List bibItems = new ArrayList<>(); try { - JAXBContext context = JAXBContext.newInstance("org.jabref.logic.importer.fileformat.medline"); - XMLInputFactory xmlInputFactory = XMLInputFactory.newFactory(); - XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(reader); - - //go to the root element - while (!xmlStreamReader.isStartElement()) { - xmlStreamReader.next(); - } - - Unmarshaller unmarshaller = context.createUnmarshaller(); - Object unmarshalledObject = unmarshaller.unmarshal(xmlStreamReader); + Object unmarshalledObject = unmarshallRoot(reader); //check whether we have an article set, an article, a book article or a book article set if (unmarshalledObject instanceof PubmedArticleSet) { @@ -185,6 +176,28 @@ public ParserResult importDatabase(BufferedReader reader) throws IOException { return new ParserResult(bibItems); } + private Object unmarshallRoot(BufferedReader reader) throws JAXBException, XMLStreamException { + initUmarshaller(); + + XMLInputFactory xmlInputFactory = XMLInputFactory.newFactory(); + XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(reader); + + //go to the root element + while (!xmlStreamReader.isStartElement()) { + xmlStreamReader.next(); + } + + return unmarshaller.unmarshal(xmlStreamReader); + } + + private void initUmarshaller() throws JAXBException { + if (unmarshaller == null) { + // Lazy init because this is expensive + JAXBContext context = JAXBContext.newInstance("org.jabref.logic.importer.fileformat.medline"); + unmarshaller = context.createUnmarshaller(); + } + } + private void parseBookArticle(PubmedBookArticle currentArticle, List bibItems) { Map fields = new HashMap<>(); if (currentArticle.getBookDocument() != null) { diff --git a/src/main/java/org/jabref/logic/util/FileType.java b/src/main/java/org/jabref/logic/util/FileType.java index fc17bb887f6..cb1de601dc0 100644 --- a/src/main/java/org/jabref/logic/util/FileType.java +++ b/src/main/java/org/jabref/logic/util/FileType.java @@ -24,8 +24,9 @@ public enum FileType { CITATION_STYLE(Localization.lang("%0 file", "CSL"), "csl"), DOCBOOK(Localization.lang("%0 file", "Docbook 4.4"), "xml"), DIN_1505(Localization.lang("%0 file", "DIN 1505"), "rtf"), - ENDNOTE(Localization.lang("%0 file", "Endnote/Refer"), "ref", "enw"), - ENDNOTE_TXT(Localization.lang("%0 file", "Endnote"), "txt"), //for export + ENDNOTE(Localization.lang("%0 file", "EndNote/Refer"), "ref", "enw"), + ENDNOTE_XML(Localization.lang("%0 file", "EndNote XML"), "xml"), + ENDNOTE_TXT(Localization.lang("%0 file", "EndNote"), "txt"), //for export FREECITE(Localization.lang("%0 file", "FreeCite"), "txt", "xml"), HARVARD_RTF(Localization.lang("%0 file", "Harvard"), "rtf"), HTML_LIST(Localization.lang("%0 file", Localization.lang("HTML list")), "html"), diff --git a/src/main/resources/xjc/endnote/RSXML.dtd b/src/main/resources/xjc/endnote/RSXML.dtd new file mode 100644 index 00000000000..32aa229358b --- /dev/null +++ b/src/main/resources/xjc/endnote/RSXML.dtd @@ -0,0 +1,168 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/java/org/jabref/logic/importer/fileformat/BibTeXMLImporterTestFiles.java b/src/test/java/org/jabref/logic/importer/fileformat/BibTeXMLImporterTestFiles.java index 0e7fc1627c1..6ab7a54ce7d 100644 --- a/src/test/java/org/jabref/logic/importer/fileformat/BibTeXMLImporterTestFiles.java +++ b/src/test/java/org/jabref/logic/importer/fileformat/BibTeXMLImporterTestFiles.java @@ -38,7 +38,7 @@ public void testIsNotRecognizedFormat(String fileName) throws IOException { @ParameterizedTest @MethodSource("fileNames") - public void testImportEntries(String fileName) throws IOException { + public void testImportEntries(String fileName) throws Exception { ImporterTestEngine.testImportEntries(new BibTeXMLImporter(), fileName, FILE_ENDING); } diff --git a/src/test/java/org/jabref/logic/importer/fileformat/BiblioscapeImporterTestFiles.java b/src/test/java/org/jabref/logic/importer/fileformat/BiblioscapeImporterTestFiles.java index 4fe1a377fa3..6c598c3c69d 100644 --- a/src/test/java/org/jabref/logic/importer/fileformat/BiblioscapeImporterTestFiles.java +++ b/src/test/java/org/jabref/logic/importer/fileformat/BiblioscapeImporterTestFiles.java @@ -25,7 +25,7 @@ public void testIsRecognizedFormat(String fileName) throws IOException { @ParameterizedTest @MethodSource("fileNames") - public void testImportEntries(String fileName) throws IOException { + public void testImportEntries(String fileName) throws Exception { ImporterTestEngine.testImportEntries(new BiblioscapeImporter(), fileName, FILE_ENDING); } } diff --git a/src/test/java/org/jabref/logic/importer/fileformat/CopacImporterTestFiles.java b/src/test/java/org/jabref/logic/importer/fileformat/CopacImporterTestFiles.java index 9947a054380..dd67ddcb7b7 100644 --- a/src/test/java/org/jabref/logic/importer/fileformat/CopacImporterTestFiles.java +++ b/src/test/java/org/jabref/logic/importer/fileformat/CopacImporterTestFiles.java @@ -36,7 +36,7 @@ public void testIsNotRecognizedFormat(String fileName) throws IOException { @ParameterizedTest @MethodSource("fileNames") - public void testImportEntries(String fileName) throws IOException { + public void testImportEntries(String fileName) throws Exception { ImporterTestEngine.testImportEntries(new CopacImporter(), fileName, FILE_ENDING); } diff --git a/src/test/java/org/jabref/logic/importer/fileformat/EndnoteXmlImporterTestFiles.java b/src/test/java/org/jabref/logic/importer/fileformat/EndnoteXmlImporterTestFiles.java new file mode 100644 index 00000000000..3cf39f99291 --- /dev/null +++ b/src/test/java/org/jabref/logic/importer/fileformat/EndnoteXmlImporterTestFiles.java @@ -0,0 +1,54 @@ +package org.jabref.logic.importer.fileformat; + +import java.io.IOException; +import java.util.function.Predicate; +import java.util.stream.Stream; + +import org.jabref.logic.importer.ImportFormatPreferences; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class EndnoteXmlImporterTestFiles { + + private static final String FILE_ENDING = ".xml"; + private ImportFormatPreferences preferences; + + private static Stream fileNames() throws IOException { + Predicate fileName = name -> name.startsWith("EndnoteXmlImporterTest") && name.endsWith(FILE_ENDING); + return ImporterTestEngine.getTestFiles(fileName).stream(); + } + + private static Stream invalidFileNames() throws IOException { + Predicate fileName = name -> !name.startsWith("EndnoteXmlImporterTest"); + return ImporterTestEngine.getTestFiles(fileName).stream(); + } + + @BeforeEach + void setUp() { + preferences = mock(ImportFormatPreferences.class); + when(preferences.getKeywordSeparator()).thenReturn(';'); + } + + @ParameterizedTest + @MethodSource("fileNames") + void testIsRecognizedFormat(String fileName) throws IOException { + ImporterTestEngine.testIsRecognizedFormat(new EndnoteXmlImporter(preferences), fileName); + } + + @ParameterizedTest + @MethodSource("invalidFileNames") + void testIsNotRecognizedFormat(String fileName) throws IOException { + ImporterTestEngine.testIsNotRecognizedFormat(new EndnoteXmlImporter(preferences), fileName); + } + + @ParameterizedTest + @MethodSource("fileNames") + void testImportEntries(String fileName) throws Exception { + ImporterTestEngine.testImportEntries(new EndnoteXmlImporter(preferences), fileName, FILE_ENDING); + } +} diff --git a/src/test/java/org/jabref/logic/importer/fileformat/ImporterTestEngine.java b/src/test/java/org/jabref/logic/importer/fileformat/ImporterTestEngine.java index 94d32a28b06..c2eaa089a38 100644 --- a/src/test/java/org/jabref/logic/importer/fileformat/ImporterTestEngine.java +++ b/src/test/java/org/jabref/logic/importer/fileformat/ImporterTestEngine.java @@ -14,7 +14,9 @@ import java.util.stream.Stream; import org.jabref.logic.bibtex.BibEntryAssert; +import org.jabref.logic.importer.ImportException; import org.jabref.logic.importer.Importer; +import org.jabref.logic.importer.ParserResult; import org.jabref.model.entry.BibEntry; import org.junit.jupiter.api.Assertions; @@ -47,9 +49,13 @@ public static void testIsNotRecognizedFormat(Importer importer, String fileName) Assertions.assertFalse(importer.isRecognizedFormat(getPath(fileName), StandardCharsets.UTF_8)); } - public static void testImportEntries(Importer importer, String fileName, String fileType) throws IOException { - List entries = importer.importDatabase(getPath(fileName), StandardCharsets.UTF_8).getDatabase() - .getEntries(); + public static void testImportEntries(Importer importer, String fileName, String fileType) throws IOException, ImportException { + ParserResult parserResult = importer.importDatabase(getPath(fileName), StandardCharsets.UTF_8); + if (parserResult.isInvalid()) { + throw new ImportException(parserResult.getErrorMessage()); + } + List entries = parserResult.getDatabase() + .getEntries(); BibEntryAssert.assertEquals(ImporterTestEngine.class, fileName.replaceAll(fileType, ".bib"), entries); } diff --git a/src/test/java/org/jabref/logic/importer/fileformat/MedlineImporterTestFiles.java b/src/test/java/org/jabref/logic/importer/fileformat/MedlineImporterTestFiles.java index a3ce1127b6b..91c49fd3d9b 100644 --- a/src/test/java/org/jabref/logic/importer/fileformat/MedlineImporterTestFiles.java +++ b/src/test/java/org/jabref/logic/importer/fileformat/MedlineImporterTestFiles.java @@ -38,7 +38,7 @@ public void testIsNotRecognizedFormat(String fileName) throws IOException { @ParameterizedTest @MethodSource("fileNames") - public void testImportEntries(String fileName) throws IOException { + public void testImportEntries(String fileName) throws Exception { ImporterTestEngine.testImportEntries(new MedlineImporter(), fileName, FILE_ENDING); } diff --git a/src/test/java/org/jabref/logic/importer/fileformat/PdfContentImporterTestFiles.java b/src/test/java/org/jabref/logic/importer/fileformat/PdfContentImporterTestFiles.java index 952664e9475..74b84bc6a3d 100644 --- a/src/test/java/org/jabref/logic/importer/fileformat/PdfContentImporterTestFiles.java +++ b/src/test/java/org/jabref/logic/importer/fileformat/PdfContentImporterTestFiles.java @@ -29,7 +29,7 @@ public void testIsRecognizedFormat(String fileName) throws IOException { @ParameterizedTest @MethodSource("fileNames") - public void testImportEntries(String fileName) throws IOException { + public void testImportEntries(String fileName) throws Exception { ImporterTestEngine.testImportEntries(new PdfContentImporter(mock(ImportFormatPreferences.class)), fileName, FILE_ENDING); } diff --git a/src/test/java/org/jabref/logic/importer/fileformat/RISImporterTestFiles.java b/src/test/java/org/jabref/logic/importer/fileformat/RISImporterTestFiles.java index 9fe87753c63..5f7782d02c7 100644 --- a/src/test/java/org/jabref/logic/importer/fileformat/RISImporterTestFiles.java +++ b/src/test/java/org/jabref/logic/importer/fileformat/RISImporterTestFiles.java @@ -24,7 +24,7 @@ public void testIsRecognizedFormat(String fileName) throws IOException { @ParameterizedTest @MethodSource("fileNames") - public void testImportEntries(String fileName) throws IOException { + public void testImportEntries(String fileName) throws Exception { ImporterTestEngine.testImportEntries(new RisImporter(), fileName, FILE_ENDING); } } diff --git a/src/test/java/org/jabref/logic/importer/fileformat/SilverPlatterImporterTest.java b/src/test/java/org/jabref/logic/importer/fileformat/SilverPlatterImporterTest.java index eac60285cb3..6b031262d3c 100644 --- a/src/test/java/org/jabref/logic/importer/fileformat/SilverPlatterImporterTest.java +++ b/src/test/java/org/jabref/logic/importer/fileformat/SilverPlatterImporterTest.java @@ -49,7 +49,7 @@ public void testIsNotRecognizedFormat(String fileName) throws IOException { @ParameterizedTest @MethodSource("fileNames") - public void testImportEntries(String fileName) throws IOException { + public void testImportEntries(String fileName) throws Exception { ImporterTestEngine.testImportEntries(testImporter, fileName, FILE_ENDING); } diff --git a/src/test/resources/org/jabref/logic/importer/fileformat/EndnoteXmlImporterTestArticle.bib b/src/test/resources/org/jabref/logic/importer/fileformat/EndnoteXmlImporterTestArticle.bib new file mode 100644 index 00000000000..f93199db1af --- /dev/null +++ b/src/test/resources/org/jabref/logic/importer/fileformat/EndnoteXmlImporterTestArticle.bib @@ -0,0 +1,16 @@ +@article{, + abstract = {test abstract}, + author = {Ahmad, AS and Ormiston-Smith, N and Sasieni, PD}, + doi = {10.1038/bjc.2014.606}, + file = {:file\://localhost/Users/user/Documents/Bookends/Attachments/Ahmad%20et%20al%202015.pdf:PDF}, + isbn = {1532-1827 (Electronic) 0007-0920 (Linking)}, + keywords = {Age Factors; Aged; Aged, 80 and over; Female; Great Britain/epidemiology; Humans; Male; Middle Aged; Models, Statistical; Neoplasms/*epidemiology; Risk Assessment; Risk Factors; Sex Characteristics}, + number = {5}, + pages = {943-7}, + title = {Trends in the lifetime risk of developing cancer in Great Britain: comparison of risk for those born from 1930 to 1960}, + volume = {112}, + year = {2015}, + journal = {Br J Cancer}, + note = {some notes}, + url = {http://www.ncbi.nlm.nih.gov/pubmed/25647015}, +} diff --git a/src/test/resources/org/jabref/logic/importer/fileformat/EndnoteXmlImporterTestArticle.xml b/src/test/resources/org/jabref/logic/importer/fileformat/EndnoteXmlImporterTestArticle.xml new file mode 100644 index 00000000000..c3a8bb5de98 --- /dev/null +++ b/src/test/resources/org/jabref/logic/importer/fileformat/EndnoteXmlImporterTestArticle.xml @@ -0,0 +1,131 @@ + + + + + Library1.bdb + Bookends + 2954 + 17 + + + + + + + + + + + + + + + + + + + <style face="normal" size="100%">Trends in the lifetime risk of developing cancer in Great Britain: + comparison of risk for those born from 1930 to 1960 + </style> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/org/jabref/logic/importer/fileformat/EndnoteXmlImporterTestArticle2.bib b/src/test/resources/org/jabref/logic/importer/fileformat/EndnoteXmlImporterTestArticle2.bib new file mode 100644 index 00000000000..a7293b79f14 --- /dev/null +++ b/src/test/resources/org/jabref/logic/importer/fileformat/EndnoteXmlImporterTestArticle2.bib @@ -0,0 +1,24 @@ +@article{, + author = {Chapman, A. G.}, + isbn = {0012-9658}, + number = {1}, + pages = {93-105}, + title = {An ecological basis for reforestation of submariginal lands in the Central Hardwood Region}, + volume = {18}, + year = {1937}, + journal = {Ecology}, + note = {some notes}, + url = {://000200148800007} +} +@book{, + author = {Strohecker, H. F.}, + isbn = {0012-9658}, + number = {1}, + journal = {Ecology}, + note = {some other notes}, + pages = {162-168}, + title = {A survey of soil temperatures in the Chicago area}, + volume = {18}, + url = {://000200148800014}, + year = {1937} +} diff --git a/src/test/resources/org/jabref/logic/importer/fileformat/EndnoteXmlImporterTestArticle2.xml b/src/test/resources/org/jabref/logic/importer/fileformat/EndnoteXmlImporterTestArticle2.xml new file mode 100644 index 00000000000..e2ff36845c1 --- /dev/null +++ b/src/test/resources/org/jabref/logic/importer/fileformat/EndnoteXmlImporterTestArticle2.xml @@ -0,0 +1,184 @@ + + + + + EndNote + Ecology.enl + + EndNote + 13264 + + 13264 + + 17 + + + + + + + + + + + + + <style face="normal" font="default" size="100%">An ecological basis for reforestation of + submariginal lands in the Central Hardwood Region + </style> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + EndNote + Ecology.enl + + EndNote + 13265 + + 13265 + + 6 + + + + + + + + + + + + + <style face="normal" font="default" size="100%">A survey of soil temperatures in the Chicago area + </style> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xjc.gradle b/xjc.gradle index 3285a93ba3e..d1d54fb5197 100644 --- a/xjc.gradle +++ b/xjc.gradle @@ -10,9 +10,11 @@ dependencies { task xjc { inputs.dir "src/main/resources/xjc/medline/" inputs.dir "src/main/resources/xjc/bibtexml/" + inputs.dir "src/main/resources/xjc/endnote/" inputs.dir "src/main/resources/xjc/mods/" outputs.dir "src/main/gen/org/jabref/logic/importer/fileformat/medline" outputs.dir "src/main/gen/org/jabref/logic/importer/fileformat/bibtexml" + outputs.dir "src/main/gen/org/jabref/logic/importer/fileformat/endnote" outputs.dir "src/main/gen/org/jabref/logic/importer/fileformat/mods" ant.taskdef(name: 'xjc', classname: 'com.sun.tools.xjc.XJCTask', classpath: configurations.xjc.asPath) @@ -24,6 +26,10 @@ task xjc { ant.xjc(destdir: 'src/main/gen/', package: 'org.jabref.logic.importer.fileformat.bibtexml') { schema(dir: 'src/main/resources/xjc/bibtexml', includes: 'bibtexml.xsd') } + ant.xjc(destdir: 'src/main/gen/', package: 'org.jabref.logic.importer.fileformat.endnote') { + arg(value: '-dtd') + schema(dir: 'src/main/resources/xjc/endnote', includes: 'RSXML.dtd') + } ant.xjc(destdir: 'src/main/gen/', package: 'org.jabref.logic.importer.fileformat.mods') { arg(value: '-npa') //don't create package-info.java because it was manually added in src/main/java to ensure the namespace prefix mapping schema(dir: 'src/main/resources/xjc/mods', includes: 'mods-3-6.xsd') From 81088459ef2b55bae7b6e47d702912a7f162bf18 Mon Sep 17 00:00:00 2001 From: Linus Dietz Date: Sat, 17 Feb 2018 07:02:25 +0100 Subject: [PATCH 45/94] Rename the Review Tab into Comments Tab (#3658) --- CHANGELOG.md | 2 + src/main/java/org/jabref/JabRefGUI.java | 3 +- src/main/java/org/jabref/gui/JabRefFrame.java | 49 ++++++----- .../java/org/jabref/gui/PreviewPanel.java | 2 +- .../AutosaveUIManager.java | 2 +- .../BackupUIManager.java | 2 +- .../MergeReviewIntoCommentUIManager.java | 31 +++++++ .../gui/exporter/SaveDatabaseAction.java | 2 +- .../importer/actions/OpenDatabaseAction.java | 2 +- .../jabref/logic/importer/OpenDatabase.java | 16 ++-- .../jabref/logic/importer/ParserResult.java | 10 ++- .../logic/importer/util/PostOpenAction.java | 7 -- .../ConvertLegacyExplicitGroups.java | 6 +- .../migrations/MergeReviewIntoComment.java | 71 ++++++++++++++++ .../jabref/migrations/PostOpenMigration.java | 7 ++ .../model/entry/InternalBibtexFields.java | 11 ++- .../jabref/preferences/JabRefPreferences.java | 6 +- src/main/resources/l10n/JabRef_en.properties | 8 +- .../ConvertLegacyExplicitGroupsTest.java | 10 +-- .../MergeReviewIntoCommentTest.java | 85 +++++++++++++++++++ 20 files changed, 265 insertions(+), 67 deletions(-) rename src/main/java/org/jabref/gui/{autosaveandbackup => dialogs}/AutosaveUIManager.java (95%) rename src/main/java/org/jabref/gui/{autosaveandbackup => dialogs}/BackupUIManager.java (96%) create mode 100644 src/main/java/org/jabref/gui/dialogs/MergeReviewIntoCommentUIManager.java delete mode 100644 src/main/java/org/jabref/logic/importer/util/PostOpenAction.java rename src/main/java/org/jabref/{logic/importer/util => migrations}/ConvertLegacyExplicitGroups.java (90%) create mode 100644 src/main/java/org/jabref/migrations/MergeReviewIntoComment.java create mode 100644 src/main/java/org/jabref/migrations/PostOpenMigration.java rename src/test/java/org/jabref/{logic/importer/util => migrations}/ConvertLegacyExplicitGroupsTest.java (91%) create mode 100644 src/test/java/org/jabref/migrations/MergeReviewIntoCommentTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index e7e82319c73..547db4d3e80 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ We refer to [GitHub issues](https://github.com/JabRef/jabref/issues) by using `# ### Changed - Abbreviate journal names functionality is now running parallel, increasing performance significantly. [#2831] (https://github.com/JabRef/jabref/issues/2831) +- Changed order of items in context menu [#298] (https://github.com/koppor/jabref/issues/298) - Changed ID-based entry generator to store the last used fetcher. [#2796] (https://github.com/JabRef/jabref/issues/2796) - Reorganised annotation information on the right side of the "File annotations" tab. [#3109](https://github.com/JabRef/jabref/issues/3109) - We now show a small notification icon in the entry editor when we detect data inconsistency or other problems. [#3145](https://github.com/JabRef/jabref/issues/3145) @@ -25,6 +26,7 @@ We refer to [GitHub issues](https://github.com/JabRef/jabref/issues) by using `# - We improved the export of the `address` and `location` field to the MS-Office XML fields. If the address field does not contain a comma, it is treated as single value and exported to the field `city`. [#1750, comment](https://github.com/JabRef/jabref/issues/1750#issuecomment-357539167) For more details refer to the [field mapping help page](http://help.jabref.org/en/MsOfficeBibFieldMapping) - We added Facebook and Twitter icons in the toolbar to link to our [Facebook](https://www.facebook.com/JabRef/) and [Twitter](https://twitter.com/jabref_org) pages. +- Renamed the _Review_ Tab into _Comments_ Tab - We no longer print empty lines when exporting an entry in RIS format [#3634](https://github.com/JabRef/jabref/issues/3634) - We improved file saving so that hard links are now preserved when a save is performed [#2633](https://github.com/JabRef/jabref/issues/2633) - We changed the default dialog option when removing a [file link](http://help.jabref.org/en/FileLinks#adding-external-links-to-an-entry) from an entry. diff --git a/src/main/java/org/jabref/JabRefGUI.java b/src/main/java/org/jabref/JabRefGUI.java index e94a6c9c367..e51014e4114 100644 --- a/src/main/java/org/jabref/JabRefGUI.java +++ b/src/main/java/org/jabref/JabRefGUI.java @@ -18,7 +18,7 @@ import org.jabref.gui.BasePanel; import org.jabref.gui.GUIGlobals; import org.jabref.gui.JabRefFrame; -import org.jabref.gui.autosaveandbackup.BackupUIManager; +import org.jabref.gui.dialogs.BackupUIManager; import org.jabref.gui.importer.ParserResultWarningDialog; import org.jabref.gui.importer.actions.OpenDatabaseAction; import org.jabref.gui.shared.SharedDatabaseUIManager; @@ -301,5 +301,4 @@ public static JabRefFrame getMainFrame() { public static void setMainFrame(JabRefFrame mainFrame) { JabRefGUI.mainFrame = mainFrame; } - } diff --git a/src/main/java/org/jabref/gui/JabRefFrame.java b/src/main/java/org/jabref/gui/JabRefFrame.java index 4abf2fbfe38..e47ff58554a 100644 --- a/src/main/java/org/jabref/gui/JabRefFrame.java +++ b/src/main/java/org/jabref/gui/JabRefFrame.java @@ -78,11 +78,11 @@ import org.jabref.gui.actions.OpenBrowserAction; import org.jabref.gui.actions.SearchForUpdateAction; import org.jabref.gui.actions.SortTabsAction; -import org.jabref.gui.autosaveandbackup.AutosaveUIManager; import org.jabref.gui.bibtexkeypattern.BibtexKeyPatternDialog; import org.jabref.gui.copyfiles.CopyFilesAction; import org.jabref.gui.customentrytypes.EntryCustomizationDialog; import org.jabref.gui.dbproperties.DatabasePropertiesDialog; +import org.jabref.gui.dialogs.AutosaveUIManager; import org.jabref.gui.documentviewer.ShowDocumentViewerAction; import org.jabref.gui.exporter.ExportAction; import org.jabref.gui.exporter.ExportCustomizationDialog; @@ -657,7 +657,6 @@ public void windowClosing(WindowEvent e) { } initShowTrackingNotification(); - } private void initShowTrackingNotification() { @@ -715,7 +714,7 @@ public void setWindowTitle() { String changeFlag = panel.isModified() && !isAutosaveEnabled ? "*" : ""; String databaseFile = panel.getBibDatabaseContext().getDatabaseFile().map(File::getPath) .orElse(GUIGlobals.UNTITLED_TITLE); - setTitle(FRAME_TITLE + " - " + databaseFile + changeFlag + modeInfo); + setTitle(FRAME_TITLE + " - " + databaseFile + changeFlag + modeInfo); } else if (panel.getBibDatabaseContext().getLocation() == DatabaseLocation.SHARED) { setTitle(FRAME_TITLE + " - " + panel.getBibDatabaseContext().getDBMSSynchronizer().getDBName() + " [" + Localization.lang("shared") + "]" + modeInfo); @@ -800,7 +799,6 @@ private void tearDownJabRef(List filenames) { File focusedDatabase = getCurrentBasePanel().getBibDatabaseContext().getDatabaseFile().orElse(null); new LastFocusedTabPreferences(prefs).setLastFocusedTab(focusedDatabase); } - } fileHistory.storeHistory(); @@ -963,7 +961,6 @@ public BasePanel getBasePanelAt(int i) { /** * Returns a list of BasePanel. - * */ public List getBasePanelList() { List returnList = new ArrayList<>(); @@ -1282,26 +1279,32 @@ private void fillMenu() { createDisabledIconsForMenuEntries(mb); } - public void addParserResult(ParserResult pr, boolean focusPanel) { - if (pr.toOpenTab()) { + public void addParserResult(ParserResult parserResult, boolean focusPanel) { + if (parserResult.toOpenTab()) { // Add the entries to the open tab. BasePanel panel = getCurrentBasePanel(); if (panel == null) { // There is no open tab to add to, so we create a new tab: - addTab(pr.getDatabaseContext(), focusPanel); + panel = addTab(parserResult.getDatabaseContext(), focusPanel); + if (parserResult.wasChangedOnMigration()) { + panel.markBaseChanged(); + } } else { - List entries = new ArrayList<>(pr.getDatabase().getEntries()); + List entries = new ArrayList<>(parserResult.getDatabase().getEntries()); addImportedEntries(panel, entries, false); } } else { // only add tab if DB is not already open Optional panel = getBasePanelList().stream() - .filter(p -> p.getBibDatabaseContext().getDatabaseFile().equals(pr.getFile())).findFirst(); + .filter(p -> p.getBibDatabaseContext().getDatabaseFile().equals(parserResult.getFile())).findFirst(); if (panel.isPresent()) { tabbedPane.setSelectedComponent(panel.get()); } else { - addTab(pr.getDatabaseContext(), focusPanel); + BasePanel basePanel = addTab(parserResult.getDatabaseContext(), focusPanel); + if (parserResult.wasChangedOnMigration()) { + basePanel.markBaseChanged(); + } } } } @@ -1447,7 +1450,6 @@ dupliCheck, autoSetFile, newEntryAction, newSpec, customizeAction, plainTextImpo atLeastOneEntryActions.addAll(Arrays.asList(downloadFullText, lookupIdentifiers, exportLinkedFiles)); tabbedPane.addChangeListener(event -> updateEnabledState()); - } /** @@ -1510,7 +1512,6 @@ public void setupAllTables() { // Update tables: if (bf.getDatabase() != null) { bf.setupMainPanel(); - } } } @@ -1561,7 +1562,7 @@ public void updateAllTabTitles() { } } - public void addTab(BasePanel basePanel, boolean raisePanel) { + public BasePanel addTab(BasePanel basePanel, boolean raisePanel) { // add tab tabbedPane.add(basePanel.getTabTitle(), basePanel); @@ -1586,22 +1587,23 @@ public void addTab(BasePanel basePanel, boolean raisePanel) { // Track opening trackOpenNewDatabase(basePanel); + return basePanel; } private void trackOpenNewDatabase(BasePanel basePanel) { Map properties = new HashMap<>(); Map measurements = new HashMap<>(); - measurements.put("NumberOfEntries", (double)basePanel.getDatabaseContext().getDatabase().getEntryCount()); + measurements.put("NumberOfEntries", (double) basePanel.getDatabaseContext().getDatabase().getEntryCount()); Globals.getTelemetryClient().ifPresent(client -> client.trackEvent("OpenNewDatabase", properties, measurements)); } public BasePanel addTab(BibDatabaseContext databaseContext, boolean raisePanel) { Objects.requireNonNull(databaseContext); - BasePanel bp = new BasePanel(JabRefFrame.this, databaseContext); - addTab(bp, raisePanel); - return bp; + BasePanel basePanel = new BasePanel(JabRefFrame.this, databaseContext); + addTab(basePanel, raisePanel); + return basePanel; } private boolean readyForAutosave(BibDatabaseContext context) { @@ -1727,7 +1729,6 @@ public void setProgressBarValue(final int value) { } else { SwingUtilities.invokeLater(() -> progressBar.setValue(value)); } - } /** @@ -1742,7 +1743,6 @@ public void setProgressBarIndeterminate(final boolean value) { } else { SwingUtilities.invokeLater(() -> progressBar.setIndeterminate(value)); } - } /** @@ -1759,11 +1759,11 @@ public void setProgressBarMaximum(final int value) { } else { SwingUtilities.invokeLater(() -> progressBar.setMaximum(value)); } - } /** * Return a boolean, if the selected entry have file + * * @param selectEntryList A selected entries list of the current base pane * @return true, if the selected entry contains file. * false, if multiple entries are selected or the selected entry doesn't contains file @@ -1778,6 +1778,7 @@ private boolean isExistFile(List selectEntryList) { /** * Return a boolean, if the selected entry have url or doi + * * @param selectEntryList A selected entries list of the current base pane * @return true, if the selected entry contains url or doi. * false, if multiple entries are selected or the selected entry doesn't contains url or doi @@ -2135,7 +2136,8 @@ public EditAction(String command, String menuTitle, String description, KeyStrok putValue(Action.SHORT_DESCRIPTION, description); } - @Override public void actionPerformed(ActionEvent e) { + @Override + public void actionPerformed(ActionEvent e) { LOGGER.debug(Globals.getFocusListener().getFocused().toString()); JComponent source = Globals.getFocusListener().getFocused(); @@ -2197,7 +2199,6 @@ public void actionPerformed(ActionEvent e) { GenFieldsCustomizer gf = new GenFieldsCustomizer(JabRefFrame.this); gf.setLocationRelativeTo(JabRefFrame.this); gf.setVisible(true); - } } @@ -2232,7 +2233,6 @@ public void actionPerformed(ActionEvent e) { propertiesDialog.setLocationRelativeTo(JabRefFrame.this); propertiesDialog.setVisible(true); } - } private class BibtexKeyPatternAction extends MnemonicAwareAction { @@ -2256,7 +2256,6 @@ public void actionPerformed(ActionEvent e) { bibtexKeyPatternDialog.setLocationRelativeTo(JabRefFrame.this); bibtexKeyPatternDialog.setVisible(true); } - } private class DefaultTableFontSizeAction extends MnemonicAwareAction { diff --git a/src/main/java/org/jabref/gui/PreviewPanel.java b/src/main/java/org/jabref/gui/PreviewPanel.java index 088c258bbd5..fedb268ae15 100644 --- a/src/main/java/org/jabref/gui/PreviewPanel.java +++ b/src/main/java/org/jabref/gui/PreviewPanel.java @@ -138,8 +138,8 @@ private ContextMenu createPopupMenu() { menu.getItems().add(copyPreview); menu.getItems().add(printEntryPreview); menu.getItems().add(new SeparatorMenuItem()); - menu.getItems().add(previousPreviewLayout); menu.getItems().add(nextPreviewLayout); + menu.getItems().add(previousPreviewLayout); return menu; } diff --git a/src/main/java/org/jabref/gui/autosaveandbackup/AutosaveUIManager.java b/src/main/java/org/jabref/gui/dialogs/AutosaveUIManager.java similarity index 95% rename from src/main/java/org/jabref/gui/autosaveandbackup/AutosaveUIManager.java rename to src/main/java/org/jabref/gui/dialogs/AutosaveUIManager.java index 99b97cf6f9d..312258be7b3 100644 --- a/src/main/java/org/jabref/gui/autosaveandbackup/AutosaveUIManager.java +++ b/src/main/java/org/jabref/gui/dialogs/AutosaveUIManager.java @@ -1,4 +1,4 @@ -package org.jabref.gui.autosaveandbackup; +package org.jabref.gui.dialogs; import org.jabref.gui.BasePanel; import org.jabref.gui.exporter.SaveDatabaseAction; diff --git a/src/main/java/org/jabref/gui/autosaveandbackup/BackupUIManager.java b/src/main/java/org/jabref/gui/dialogs/BackupUIManager.java similarity index 96% rename from src/main/java/org/jabref/gui/autosaveandbackup/BackupUIManager.java rename to src/main/java/org/jabref/gui/dialogs/BackupUIManager.java index 3e0e3be4571..17256318f79 100644 --- a/src/main/java/org/jabref/gui/autosaveandbackup/BackupUIManager.java +++ b/src/main/java/org/jabref/gui/dialogs/BackupUIManager.java @@ -1,4 +1,4 @@ -package org.jabref.gui.autosaveandbackup; +package org.jabref.gui.dialogs; import java.nio.file.Path; diff --git a/src/main/java/org/jabref/gui/dialogs/MergeReviewIntoCommentUIManager.java b/src/main/java/org/jabref/gui/dialogs/MergeReviewIntoCommentUIManager.java new file mode 100644 index 00000000000..4e03dad775c --- /dev/null +++ b/src/main/java/org/jabref/gui/dialogs/MergeReviewIntoCommentUIManager.java @@ -0,0 +1,31 @@ +package org.jabref.gui.dialogs; + +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import javax.swing.JOptionPane; + +import org.jabref.logic.l10n.Localization; +import org.jabref.model.entry.BibEntry; + +public class MergeReviewIntoCommentUIManager { + + public boolean askUserForMerge(List conflicts) { + List bibKeys = conflicts.stream() + .map(BibEntry::getCiteKeyOptional) + .filter(Optional::isPresent) + .map(Optional::get) + .collect(Collectors.toList()); + + int answer = JOptionPane.showConfirmDialog( + null, + String.join(",\n", bibKeys) + " " + + Localization.lang("has/have both a 'Comment' and a 'Review' field.") + "\n" + + Localization.lang("Since the 'Review' field was deprecated in JabRef 4.2, these two fields are about to be merged into the 'Comment' field.") + "\n" + + Localization.lang("The conflicting fields of these entries will be merged into the 'Comment' field."), + Localization.lang("Review Field Migration"), JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE); + + return 0 == answer; + } +} diff --git a/src/main/java/org/jabref/gui/exporter/SaveDatabaseAction.java b/src/main/java/org/jabref/gui/exporter/SaveDatabaseAction.java index 720422289f4..315a70497d5 100644 --- a/src/main/java/org/jabref/gui/exporter/SaveDatabaseAction.java +++ b/src/main/java/org/jabref/gui/exporter/SaveDatabaseAction.java @@ -16,9 +16,9 @@ import org.jabref.gui.DialogService; import org.jabref.gui.FXDialogService; import org.jabref.gui.JabRefFrame; -import org.jabref.gui.autosaveandbackup.AutosaveUIManager; import org.jabref.gui.collab.ChangeScanner; import org.jabref.gui.collab.FileUpdatePanel; +import org.jabref.gui.dialogs.AutosaveUIManager; import org.jabref.gui.util.DefaultTaskExecutor; import org.jabref.gui.util.FileDialogConfiguration; import org.jabref.gui.worker.AbstractWorker; diff --git a/src/main/java/org/jabref/gui/importer/actions/OpenDatabaseAction.java b/src/main/java/org/jabref/gui/importer/actions/OpenDatabaseAction.java index cfbcd91fc27..6a4b0dd6736 100644 --- a/src/main/java/org/jabref/gui/importer/actions/OpenDatabaseAction.java +++ b/src/main/java/org/jabref/gui/importer/actions/OpenDatabaseAction.java @@ -26,7 +26,7 @@ import org.jabref.gui.IconTheme; import org.jabref.gui.JabRefFrame; import org.jabref.gui.actions.MnemonicAwareAction; -import org.jabref.gui.autosaveandbackup.BackupUIManager; +import org.jabref.gui.dialogs.BackupUIManager; import org.jabref.gui.importer.ParserResultWarningDialog; import org.jabref.gui.keyboard.KeyBinding; import org.jabref.gui.shared.SharedDatabaseUIManager; diff --git a/src/main/java/org/jabref/logic/importer/OpenDatabase.java b/src/main/java/org/jabref/logic/importer/OpenDatabase.java index c9e2acfac26..1c3197e0e7b 100644 --- a/src/main/java/org/jabref/logic/importer/OpenDatabase.java +++ b/src/main/java/org/jabref/logic/importer/OpenDatabase.java @@ -6,11 +6,12 @@ import java.util.List; import org.jabref.logic.importer.fileformat.BibtexImporter; -import org.jabref.logic.importer.util.ConvertLegacyExplicitGroups; -import org.jabref.logic.importer.util.PostOpenAction; import org.jabref.logic.l10n.Localization; import org.jabref.logic.specialfields.SpecialFieldsUtils; import org.jabref.logic.util.io.FileBasedLock; +import org.jabref.migrations.ConvertLegacyExplicitGroups; +import org.jabref.migrations.MergeReviewIntoComment; +import org.jabref.migrations.PostOpenMigration; import org.jabref.model.entry.BibEntry; import org.jabref.model.util.FileUpdateMonitor; @@ -81,16 +82,17 @@ public static ParserResult loadDatabase(File fileToOpen, ImportFormatPreferences LOGGER.debug("Synchronized special fields based on keywords"); } - applyPostActions(result); + performLoadDatabaseMigrations(result); return result; } - private static void applyPostActions(ParserResult parserResult) { - List actions = Arrays.asList(new ConvertLegacyExplicitGroups()); + private static void performLoadDatabaseMigrations(ParserResult parserResult) { - for (PostOpenAction action : actions) { - action.performAction(parserResult); + List postOpenMigrations = Arrays.asList(new ConvertLegacyExplicitGroups(), new MergeReviewIntoComment()); + + for (PostOpenMigration migration : postOpenMigrations) { + migration.performMigration(parserResult); } } } diff --git a/src/main/java/org/jabref/logic/importer/ParserResult.java b/src/main/java/org/jabref/logic/importer/ParserResult.java index d6374cdde33..a19b5020a2d 100644 --- a/src/main/java/org/jabref/logic/importer/ParserResult.java +++ b/src/main/java/org/jabref/logic/importer/ParserResult.java @@ -19,7 +19,6 @@ import org.jabref.model.metadata.MetaData; public class ParserResult { - private final Map entryTypes; private final List warnings = new ArrayList<>(); private final List duplicateKeys = new ArrayList<>(); @@ -28,6 +27,7 @@ public class ParserResult { private File file; private boolean invalid; private boolean toOpenTab; + private boolean changedOnMigration = false; public ParserResult() { this(Collections.emptyList()); @@ -180,4 +180,12 @@ public void setDatabaseContext(BibDatabaseContext bibDatabaseContext) { public boolean isEmpty() { return this == new ParserResult(); } + + public boolean wasChangedOnMigration() { + return changedOnMigration; + } + + public void setChangedOnMigration(boolean wasChangedOnMigration) { + this.changedOnMigration = wasChangedOnMigration; + } } diff --git a/src/main/java/org/jabref/logic/importer/util/PostOpenAction.java b/src/main/java/org/jabref/logic/importer/util/PostOpenAction.java deleted file mode 100644 index 7eadee68c88..00000000000 --- a/src/main/java/org/jabref/logic/importer/util/PostOpenAction.java +++ /dev/null @@ -1,7 +0,0 @@ -package org.jabref.logic.importer.util; - -import org.jabref.logic.importer.ParserResult; - -public interface PostOpenAction { - void performAction(ParserResult parserResult); -} diff --git a/src/main/java/org/jabref/logic/importer/util/ConvertLegacyExplicitGroups.java b/src/main/java/org/jabref/migrations/ConvertLegacyExplicitGroups.java similarity index 90% rename from src/main/java/org/jabref/logic/importer/util/ConvertLegacyExplicitGroups.java rename to src/main/java/org/jabref/migrations/ConvertLegacyExplicitGroups.java index 6cb4f839be3..d0f5ced7bfc 100644 --- a/src/main/java/org/jabref/logic/importer/util/ConvertLegacyExplicitGroups.java +++ b/src/main/java/org/jabref/migrations/ConvertLegacyExplicitGroups.java @@ -1,4 +1,4 @@ -package org.jabref.logic.importer.util; +package org.jabref.migrations; import java.util.ArrayList; import java.util.List; @@ -13,10 +13,10 @@ * Converts legacy explicit groups, where the group contained a list of assigned entries, to the new format, * where the entry stores a list of groups it belongs to. */ -public class ConvertLegacyExplicitGroups implements PostOpenAction { +public class ConvertLegacyExplicitGroups implements PostOpenMigration { @Override - public void performAction(ParserResult parserResult) { + public void performMigration(ParserResult parserResult) { Objects.requireNonNull(parserResult); if (!parserResult.getMetaData().getGroups().isPresent()) { return; diff --git a/src/main/java/org/jabref/migrations/MergeReviewIntoComment.java b/src/main/java/org/jabref/migrations/MergeReviewIntoComment.java new file mode 100644 index 00000000000..76280caa24a --- /dev/null +++ b/src/main/java/org/jabref/migrations/MergeReviewIntoComment.java @@ -0,0 +1,71 @@ +package org.jabref.migrations; + +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +import javafx.collections.ObservableList; + +import org.jabref.gui.dialogs.MergeReviewIntoCommentUIManager; +import org.jabref.logic.importer.ParserResult; +import org.jabref.logic.l10n.Localization; +import org.jabref.model.entry.BibEntry; +import org.jabref.model.entry.FieldName; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class MergeReviewIntoComment implements PostOpenMigration { + public static final Logger LOGGER = LoggerFactory.getLogger(MergeReviewIntoComment.class); + + @Override + public void performMigration(ParserResult parserResult) { + ObservableList entries = Objects.requireNonNull(parserResult).getDatabase().getEntries(); + + // migrate non-conflicting entries first + entries.stream() + .filter(this::hasReviewField) + .filter(entry -> !this.hasCommentField(entry)) + .forEach(entry -> migrate(entry, parserResult)); + + // determine conflicts + List conflicts = entries.stream() + .filter(this::hasReviewField) + .filter(this::hasCommentField) + .collect(Collectors.toList()); + + // resolve conflicts if users agrees + if (!conflicts.isEmpty() && new MergeReviewIntoCommentUIManager().askUserForMerge(conflicts)) { + conflicts.stream() + .filter(this::hasReviewField) + .forEach(entry -> migrate(entry, parserResult)); + } + } + + private String mergeCommentFieldIfPresent(BibEntry entry, String review) { + if (entry.getField(FieldName.COMMENT).isPresent()) { + LOGGER.info(String.format("Both Comment and Review fields are present in %s! Merging them into the comment field.", entry.getAuthorTitleYear(150))); + return String.format("%s\n%s:\n%s", entry.getField(FieldName.COMMENT).get().trim(), Localization.lang("Review"), review.trim()); + } + return review; + } + + private boolean hasCommentField(BibEntry entry) { + return entry.getField(FieldName.COMMENT).isPresent(); + } + + private boolean hasReviewField(BibEntry entry) { + return entry.getField(FieldName.REVIEW).isPresent(); + } + + private void migrate(BibEntry entry, ParserResult parserResult) { + // this method may only be called if the review field is present + updateFields(entry, mergeCommentFieldIfPresent(entry, entry.getField(FieldName.REVIEW).get())); + parserResult.wasChangedOnMigration(); + } + + private void updateFields(BibEntry entry, String review) { + entry.setField(FieldName.COMMENT, review); + entry.clearField(FieldName.REVIEW); + } +} diff --git a/src/main/java/org/jabref/migrations/PostOpenMigration.java b/src/main/java/org/jabref/migrations/PostOpenMigration.java new file mode 100644 index 00000000000..b259ee12cb3 --- /dev/null +++ b/src/main/java/org/jabref/migrations/PostOpenMigration.java @@ -0,0 +1,7 @@ +package org.jabref.migrations; + +import org.jabref.logic.importer.ParserResult; + +public interface PostOpenMigration { + void performMigration(ParserResult parserResult); +} diff --git a/src/main/java/org/jabref/model/entry/InternalBibtexFields.java b/src/main/java/org/jabref/model/entry/InternalBibtexFields.java index 3cf4886c36f..69c8302a3df 100644 --- a/src/main/java/org/jabref/model/entry/InternalBibtexFields.java +++ b/src/main/java/org/jabref/model/entry/InternalBibtexFields.java @@ -22,10 +22,10 @@ * config files -> simple extension and definition of new fields * * TODO: - * - handling of identically fields with different names (https://github.com/JabRef/jabref/issues/521) - * e.g. LCCN = lib-congress, journaltitle = journal - * - group id for each fields, e.g. standard, jurabib, bio, ... - * - add a additional properties functionality into the BibtexSingleField class + * - handling of identically fields with different names (https://github.com/JabRef/jabref/issues/521) + * e.g. LCCN = lib-congress, journaltitle = journal + * - group id for each fields, e.g. standard, jurabib, bio, ... + * - add a additional properties functionality into the BibtexSingleField class */ public class InternalBibtexFields { @@ -35,7 +35,7 @@ public class InternalBibtexFields { * * A user can change them. The change is currently stored in the preferences only and not explicitley exposed as separte preferences object */ - public static final List DEFAULT_GENERAL_FIELDS = Arrays.asList(FieldName.CROSSREF, FieldName.KEYWORDS, FieldName.FILE, FieldName.DOI, FieldName.URL, FieldName.GROUPS, FieldName.COMMENT, FieldName.OWNER, FieldName.TIMESTAMP); + public static final List DEFAULT_GENERAL_FIELDS = Arrays.asList(FieldName.CROSSREF, FieldName.KEYWORDS, FieldName.FILE, FieldName.DOI, FieldName.URL, FieldName.GROUPS, FieldName.OWNER, FieldName.TIMESTAMP); // Lists of fields with special properties private static final List INTEGER_FIELDS = Arrays.asList(FieldName.CTLMAX_NAMES_FORCED_ETAL, @@ -382,7 +382,6 @@ public static void setNumericFields(List numFields) { field.setNumeric(true); InternalBibtexFields.RUNTIME.fieldSet.put(fieldName, field); } - } public static Set getFieldProperties(String name) { diff --git a/src/main/java/org/jabref/preferences/JabRefPreferences.java b/src/main/java/org/jabref/preferences/JabRefPreferences.java index 149dec57782..91179882f38 100644 --- a/src/main/java/org/jabref/preferences/JabRefPreferences.java +++ b/src/main/java/org/jabref/preferences/JabRefPreferences.java @@ -982,9 +982,9 @@ public void setLanguageDependentDefaultValues() { defaults.put(CUSTOM_TAB_FIELDS + "_def1", FieldName.ABSTRACT); defaults.put(CUSTOM_TAB_NAME + "_def1", Localization.lang("Abstract")); - // Entry editor tab 2: Review Field - used for research comments, etc. - defaults.put(CUSTOM_TAB_FIELDS + "_def2", FieldName.REVIEW); - defaults.put(CUSTOM_TAB_NAME + "_def2", Localization.lang("Review")); + // Entry editor tab 2: Comments Field - used for research comments, etc. + defaults.put(CUSTOM_TAB_FIELDS + "_def2", FieldName.COMMENT); + defaults.put(CUSTOM_TAB_NAME + "_def2", Localization.lang("Comments")); defaults.put(EMAIL_SUBJECT, Localization.lang("References")); } diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties index f9cc9db3029..6b4b8ea1d3d 100644 --- a/src/main/resources/l10n/JabRef_en.properties +++ b/src/main/resources/l10n/JabRef_en.properties @@ -148,6 +148,7 @@ Broken\ link=Broken link Browse=Browse by=by +The\ conflicting\ fields\ of\ these\ entries\ will\ be\ merged\ into\ the\ 'Comment'\ field.=The conflicting fields of these entries will be merged into the 'Comment' field. Cancel=Cancel @@ -210,7 +211,7 @@ Color\ for\ marking\ incomplete\ entries=Color for marking incomplete entries Column\ width=Column width Command\ line\ id=Command line id - +Comments=Comments Contained\ in=Contained in @@ -560,6 +561,7 @@ Get\ fulltext=Get fulltext Gray\ out\ non-hits=Gray out non-hits Groups=Groups +has/have\ both\ a\ 'Comment'\ and\ a\ 'Review'\ field.=has/have both a 'Comment' and a 'Review' field. Have\ you\ chosen\ the\ correct\ package\ path?=Have you chosen the correct package path? @@ -1007,10 +1009,9 @@ Resolve\ strings\ for\ all\ fields\ except=Resolve strings for all fields except Resolve\ strings\ for\ standard\ BibTeX\ fields\ only=Resolve strings for standard BibTeX fields only resolved=resolved - Review=Review - Review\ changes=Review changes +Review\ Field\ Migration=Review Field Migration Right=Right @@ -1103,6 +1104,7 @@ Show\ URL/DOI\ column=Show URL/DOI column Show\ validation\ messages=Show validation messages Simple\ HTML=Simple HTML +Since\ the\ 'Review'\ field\ was\ deprecated\ in\ JabRef\ 4.2,\ these\ two\ fields\ are\ about\ to\ be\ merged\ into\ the\ 'Comment'\ field.=Since the 'Review' field was deprecated in JabRef 4.2, these two fields are about to be merged into the 'Comment' field. Size=Size diff --git a/src/test/java/org/jabref/logic/importer/util/ConvertLegacyExplicitGroupsTest.java b/src/test/java/org/jabref/migrations/ConvertLegacyExplicitGroupsTest.java similarity index 91% rename from src/test/java/org/jabref/logic/importer/util/ConvertLegacyExplicitGroupsTest.java rename to src/test/java/org/jabref/migrations/ConvertLegacyExplicitGroupsTest.java index a01fdec06dd..2d46cf37ed3 100644 --- a/src/test/java/org/jabref/logic/importer/util/ConvertLegacyExplicitGroupsTest.java +++ b/src/test/java/org/jabref/migrations/ConvertLegacyExplicitGroupsTest.java @@ -1,4 +1,4 @@ -package org.jabref.logic.importer.util; +package org.jabref.migrations; import java.util.Collections; import java.util.Optional; @@ -17,7 +17,7 @@ public class ConvertLegacyExplicitGroupsTest { - private PostOpenAction action; + private PostOpenMigration action; private BibEntry entry; private ExplicitGroup group; @@ -35,7 +35,7 @@ public void setUp() throws Exception { public void performActionWritesGroupMembershipInEntry() throws Exception { ParserResult parserResult = generateParserResult(GroupTreeNode.fromGroup(group)); - action.performAction(parserResult); + action.performMigration(parserResult); assertEquals(Optional.of("TestGroup"), entry.getField("groups")); } @@ -44,7 +44,7 @@ public void performActionWritesGroupMembershipInEntry() throws Exception { public void performActionClearsLegacyKeys() throws Exception { ParserResult parserResult = generateParserResult(GroupTreeNode.fromGroup(group)); - action.performAction(parserResult); + action.performMigration(parserResult); assertEquals(Collections.emptyList(), group.getLegacyEntryKeys()); } @@ -56,7 +56,7 @@ public void performActionWritesGroupMembershipInEntryForComplexGroupTree() throw root.addSubgroup(group); ParserResult parserResult = generateParserResult(root); - action.performAction(parserResult); + action.performMigration(parserResult); assertEquals(Optional.of("TestGroup"), entry.getField("groups")); } diff --git a/src/test/java/org/jabref/migrations/MergeReviewIntoCommentTest.java b/src/test/java/org/jabref/migrations/MergeReviewIntoCommentTest.java new file mode 100644 index 00000000000..b142e86a46c --- /dev/null +++ b/src/test/java/org/jabref/migrations/MergeReviewIntoCommentTest.java @@ -0,0 +1,85 @@ +package org.jabref.migrations; + +import java.util.Collections; + +import org.jabref.logic.importer.ParserResult; +import org.jabref.logic.l10n.Localization; +import org.jabref.model.entry.BibEntry; +import org.jabref.model.entry.FieldName; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class MergeReviewIntoCommentTest { + + private MergeReviewIntoComment action; + + @BeforeEach + public void setUp() { + action = new MergeReviewIntoComment(); + } + + @Test + public void noFields() { + BibEntry entry = createMinimalBibEntry(); + ParserResult actualParserResult = new ParserResult(Collections.singletonList(entry)); + + action.performMigration(actualParserResult); + + assertEquals(entry, actualParserResult.getDatabase().getEntryByKey("Entry1").get()); + } + + @Test + public void reviewField() { + BibEntry actualEntry = createMinimalBibEntry(); + actualEntry.setField(FieldName.REVIEW, "My Review"); + ParserResult actualParserResult = new ParserResult(Collections.singletonList(actualEntry)); + + BibEntry expectedEntry = createMinimalBibEntry(); + expectedEntry.setField(FieldName.COMMENT, "My Review"); + + action.performMigration(actualParserResult); + + assertEquals(expectedEntry, actualParserResult.getDatabase().getEntryByKey("Entry1").get()); + } + + @Test + public void commentField() { + BibEntry entry = createMinimalBibEntry(); + entry.setField(FieldName.COMMENT, "My Comment"); + ParserResult actualParserResult = new ParserResult(Collections.singletonList(entry)); + + action.performMigration(actualParserResult); + + assertEquals(entry, actualParserResult.getDatabase().getEntryByKey("Entry1").get()); + } + + + @Test + @Disabled("Re-enable if the MergeReviewIntoComment.mergeCommentFieldIfPresent() does not block and wait for user input.") + public void reviewAndCommentField() { + BibEntry actualEntry = createMinimalBibEntry(); + actualEntry.setField(FieldName.REVIEW, "My Review"); + actualEntry.setField(FieldName.COMMENT, "My Comment"); + + ParserResult actualParserResult = new ParserResult(Collections.singletonList(actualEntry)); + + BibEntry expectedEntry = createMinimalBibEntry(); + expectedEntry.setField(FieldName.COMMENT, "My Comment\n" + Localization.lang("Review") + ":\nMy Review"); + + action.performMigration(actualParserResult); + + assertEquals(expectedEntry, actualParserResult.getDatabase().getEntryByKey("Entry1").get()); + } + + private BibEntry createMinimalBibEntry() { + BibEntry entry = new BibEntry(); + entry.setCiteKey("Entry1"); + entry.setField(FieldName.TITLE, "A random entry!"); + entry.setField(FieldName.AUTHOR, "JabRef DEVELOPERS"); + return entry; + } +} From 76a71d35be7b22bc119e041463fcf4c571fe1ac7 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Sat, 17 Feb 2018 07:11:20 +0100 Subject: [PATCH 46/94] New translations JabRef_en.properties (French) --- src/main/resources/l10n/JabRef_fr.properties | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/resources/l10n/JabRef_fr.properties b/src/main/resources/l10n/JabRef_fr.properties index 57607b07972..8170ee3049a 100644 --- a/src/main/resources/l10n/JabRef_fr.properties +++ b/src/main/resources/l10n/JabRef_fr.properties @@ -212,7 +212,6 @@ Column\ width=Largeur de colonne Command\ line\ id=Identifiant de la ligne de commande - Contained\ in=Contenu dans Content=Contenu @@ -1008,9 +1007,7 @@ Resolve\ strings\ for\ all\ fields\ except=Traiter les chaînes pour tous les ch Resolve\ strings\ for\ standard\ BibTeX\ fields\ only=Traiter les chaînes pour les champs BibTeX standard uniquement resolved=résolu - Review=Remarques - Review\ changes=Revoir les changements Right=Droite From 3f720952a4faa056381c85546095dc08239d0605 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Sat, 17 Feb 2018 07:11:24 +0100 Subject: [PATCH 47/94] New translations JabRef_en.properties (Turkish) --- src/main/resources/l10n/JabRef_tr.properties | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/resources/l10n/JabRef_tr.properties b/src/main/resources/l10n/JabRef_tr.properties index fe48ab4f42f..46b1d8f21bc 100644 --- a/src/main/resources/l10n/JabRef_tr.properties +++ b/src/main/resources/l10n/JabRef_tr.properties @@ -212,7 +212,6 @@ Column\ width=Sütun genişliği Command\ line\ id=Komut satır no - Contained\ in=Şunun içinde Content=İçerik @@ -1004,9 +1003,7 @@ Resolve\ strings\ for\ all\ fields\ except=Şu hariç tüm alanların dizgelerin Resolve\ strings\ for\ standard\ BibTeX\ fields\ only=Yalnızca standart BibTeX alan dizgelerini çözümle resolved=çözümlendi - Review=Gözden geçir - Review\ changes=Değişklikleri incele Right=Sağ From 40e57c250ce564f41bd98a16f95885b68baf7eab Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Sat, 17 Feb 2018 07:11:27 +0100 Subject: [PATCH 48/94] New translations JabRef_en.properties (Swedish) --- src/main/resources/l10n/JabRef_sv.properties | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/resources/l10n/JabRef_sv.properties b/src/main/resources/l10n/JabRef_sv.properties index 22b73f393a9..4c6011b4f58 100644 --- a/src/main/resources/l10n/JabRef_sv.properties +++ b/src/main/resources/l10n/JabRef_sv.properties @@ -203,7 +203,6 @@ Column\ width=Kolumnbredd Command\ line\ id=Kommandorads-id - Contained\ in=Finns i Content=Innehåll @@ -934,8 +933,6 @@ Reset\ all=Återställ alla Resolve\ strings\ for\ all\ fields\ except=Ersätt strängar för alla fält utom Resolve\ strings\ for\ standard\ BibTeX\ fields\ only=Ersätt bara strängar för de vanliga BibTeX-fälten - - Review\ changes=Kontrollera ändringar Right=Höger From 92179f70d087263255a5dd44339508f7ae13a463 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Sat, 17 Feb 2018 07:11:30 +0100 Subject: [PATCH 49/94] New translations JabRef_en.properties (Spanish) --- src/main/resources/l10n/JabRef_es.properties | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/resources/l10n/JabRef_es.properties b/src/main/resources/l10n/JabRef_es.properties index 1be1e1ba8c6..213de61369b 100644 --- a/src/main/resources/l10n/JabRef_es.properties +++ b/src/main/resources/l10n/JabRef_es.properties @@ -211,7 +211,6 @@ Column\ width=Ancho de columna Command\ line\ id=Id de línea de comando - Contained\ in=Contenido en Content=Contenido @@ -996,9 +995,7 @@ Resolve\ strings\ for\ all\ fields\ except=Resolver cadenas para todos los campo Resolve\ strings\ for\ standard\ BibTeX\ fields\ only=Resolver cadenas únicamente para los campos BibTeX estándar resolved=resuelto - Review=Revisar - Review\ changes=Revisar cambios Right=Derecha From fcb279f5772115f00bcf32ae906b0abbd0dbf45f Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Sat, 17 Feb 2018 07:11:32 +0100 Subject: [PATCH 50/94] New translations JabRef_en.properties (Russian) --- src/main/resources/l10n/JabRef_ru.properties | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/resources/l10n/JabRef_ru.properties b/src/main/resources/l10n/JabRef_ru.properties index 48ff84e75fd..cec39ed82db 100644 --- a/src/main/resources/l10n/JabRef_ru.properties +++ b/src/main/resources/l10n/JabRef_ru.properties @@ -209,7 +209,6 @@ Column\ width=Ширина столбца Command\ line\ id=Ид. командной строки - Contained\ in=Содержится в Content=Содержимое @@ -975,9 +974,7 @@ Resolve\ strings\ for\ all\ fields\ except=Разрешение для стро Resolve\ strings\ for\ standard\ BibTeX\ fields\ only=Разрешение для строк только стандартных полей BibTeX resolved=разрешено - Review=Просмотр - Review\ changes=Просмотр изменений Right=Справа From d9d4bab12481af80efc05d3a822d0441a865db00 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Sat, 17 Feb 2018 07:11:35 +0100 Subject: [PATCH 51/94] New translations JabRef_en.properties (Portuguese, Brazilian) --- src/main/resources/l10n/JabRef_pt_BR.properties | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/resources/l10n/JabRef_pt_BR.properties b/src/main/resources/l10n/JabRef_pt_BR.properties index ff8647825e0..1a449faa984 100644 --- a/src/main/resources/l10n/JabRef_pt_BR.properties +++ b/src/main/resources/l10n/JabRef_pt_BR.properties @@ -208,7 +208,6 @@ Column\ width=Largura da coluna Command\ line\ id=ID da linha de comando - Contained\ in=Contido em Content=Conteúdo @@ -968,9 +967,7 @@ Resolve\ strings\ for\ all\ fields\ except=Resolver strings para todos os campos Resolve\ strings\ for\ standard\ BibTeX\ fields\ only=Resolver strings apenas para campos BibTeX padrões resolved=resolvido - Review=Revisar - Review\ changes=Revisar mudanças Right=Direito From dc45daeb9c30bf2f405d7ed000ed3bdadf6e66fb Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Sat, 17 Feb 2018 07:11:38 +0100 Subject: [PATCH 52/94] New translations JabRef_en.properties (Persian) --- src/main/resources/l10n/JabRef_fa.properties | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/resources/l10n/JabRef_fa.properties b/src/main/resources/l10n/JabRef_fa.properties index 219a94504af..6d621c33370 100644 --- a/src/main/resources/l10n/JabRef_fa.properties +++ b/src/main/resources/l10n/JabRef_fa.properties @@ -140,7 +140,6 @@ - Delete\ entry=حذف مدخل @@ -604,8 +603,6 @@ Open\ terminal\ here=در اینجا پایانه را باز کن - - From caa8f536a1a643a4e31f40c3da28a0404498cafc Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Sat, 17 Feb 2018 07:11:42 +0100 Subject: [PATCH 53/94] New translations JabRef_en.properties (Norwegian) --- src/main/resources/l10n/JabRef_no.properties | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/resources/l10n/JabRef_no.properties b/src/main/resources/l10n/JabRef_no.properties index 22253c3d7fd..0e729abc017 100644 --- a/src/main/resources/l10n/JabRef_no.properties +++ b/src/main/resources/l10n/JabRef_no.properties @@ -205,7 +205,6 @@ Column\ width=Kolonnebredde Command\ line\ id=Kommandolinje-id - Contained\ in=Inneholdt i Content=Innhold @@ -957,9 +956,7 @@ Resolve\ strings\ for\ all\ fields\ except=Slå opp strenger for alle felter unn Resolve\ strings\ for\ standard\ BibTeX\ fields\ only=Slå opp strenger kun for standard BibTeX-felter resolved=tatt hånd om - Review=Kommentarer - Review\ changes=Se over endringer Right=Høyre From 9b9972f2ac845c278226a849324f7e71f30e69ab Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Sat, 17 Feb 2018 07:11:44 +0100 Subject: [PATCH 54/94] New translations JabRef_en.properties (Japanese) --- src/main/resources/l10n/JabRef_ja.properties | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/resources/l10n/JabRef_ja.properties b/src/main/resources/l10n/JabRef_ja.properties index dba7ca990de..e601bcd5e13 100644 --- a/src/main/resources/l10n/JabRef_ja.properties +++ b/src/main/resources/l10n/JabRef_ja.properties @@ -212,7 +212,6 @@ Column\ width=列幅 Command\ line\ id=コマンドラインID - Contained\ in=所在 Content=内容 @@ -1005,9 +1004,7 @@ Resolve\ strings\ for\ all\ fields\ except=文字列を以下を除いた全フ Resolve\ strings\ for\ standard\ BibTeX\ fields\ only=文字列をBibTeX標準フィールドでのみ展開する resolved=解消しました - Review=論評 - Review\ changes=変更を検査する Right=右側 From 299986a978f9bd1a4ff0ed4d50034b46eb42470c Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Sat, 17 Feb 2018 07:11:48 +0100 Subject: [PATCH 55/94] New translations JabRef_en.properties (Chinese Simplified) --- src/main/resources/l10n/JabRef_zh.properties | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/resources/l10n/JabRef_zh.properties b/src/main/resources/l10n/JabRef_zh.properties index 6501515b830..5c9064bdcc0 100644 --- a/src/main/resources/l10n/JabRef_zh.properties +++ b/src/main/resources/l10n/JabRef_zh.properties @@ -210,7 +210,6 @@ Column\ width=列宽 Command\ line\ id=命令行 id - Contained\ in=包含在 Content=内容 @@ -995,9 +994,7 @@ Resolve\ strings\ for\ all\ fields\ except=处理所有域的简写字串,除 Resolve\ strings\ for\ standard\ BibTeX\ fields\ only=只处理标准 BibTeX 域的简写字串 resolved=已解决 - Review=评论 - Review\ changes=复查修改 Right=右 From 41394321f81587b9b066c21b61d525c0d3e64394 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Sat, 17 Feb 2018 07:11:50 +0100 Subject: [PATCH 56/94] New translations JabRef_en.properties (Danish) --- src/main/resources/l10n/JabRef_da.properties | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/resources/l10n/JabRef_da.properties b/src/main/resources/l10n/JabRef_da.properties index 38495a2215f..14c572510e3 100644 --- a/src/main/resources/l10n/JabRef_da.properties +++ b/src/main/resources/l10n/JabRef_da.properties @@ -206,7 +206,6 @@ Column\ width=Kolonnebredde Command\ line\ id=Kommandolinje-id - Contained\ in=Indeholdt i Content=Indhold @@ -960,9 +959,7 @@ Resolve\ strings\ for\ all\ fields\ except=Slå strenge op for alle felter undta Resolve\ strings\ for\ standard\ BibTeX\ fields\ only=Slå kun strenge op for standard BibTeX-felter resolved=løst - Review=Kommentarer - Review\ changes=Gennemse ændringer Right=Højre From 7226a010621c52402fb8e9e6f714b4bbce059de2 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Sat, 17 Feb 2018 07:11:54 +0100 Subject: [PATCH 57/94] New translations JabRef_en.properties (Dutch) --- src/main/resources/l10n/JabRef_nl.properties | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/resources/l10n/JabRef_nl.properties b/src/main/resources/l10n/JabRef_nl.properties index fb74a7317a8..332b676b58b 100644 --- a/src/main/resources/l10n/JabRef_nl.properties +++ b/src/main/resources/l10n/JabRef_nl.properties @@ -196,7 +196,6 @@ Column\ width=Kolombreedte Command\ line\ id=Commandoregel id - Contained\ in=bevat in Content=Inhoud @@ -888,9 +887,7 @@ Reset\ all=Herstel alles resolved=opgelost - Review=Recensie - Review\ changes=Bekijk veranderingen Right=Rechts From e777aafadbb895c48d002ee8682caddb05c9c972 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Sat, 17 Feb 2018 07:11:57 +0100 Subject: [PATCH 58/94] New translations JabRef_en.properties (German) --- src/main/resources/l10n/JabRef_de.properties | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/resources/l10n/JabRef_de.properties b/src/main/resources/l10n/JabRef_de.properties index 194ea045c7b..d395de8298b 100644 --- a/src/main/resources/l10n/JabRef_de.properties +++ b/src/main/resources/l10n/JabRef_de.properties @@ -212,7 +212,6 @@ Column\ width=Spaltenbreite Command\ line\ id=Kommandozeilen ID - Contained\ in=Enthalten in Content=Inhalt @@ -1005,9 +1004,7 @@ Resolve\ strings\ for\ all\ fields\ except=Strings auflösen für alle Felder au Resolve\ strings\ for\ standard\ BibTeX\ fields\ only=Strings nur für Standard-BibTeX-Felder auflösen resolved=davon aufgelöst - Review=Überprüfung - Review\ changes=Änderungen überprüfen Right=Rechts From b337c0bc0c639fedf9d34e915f73e47e0c02e6e3 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Sat, 17 Feb 2018 07:12:01 +0100 Subject: [PATCH 59/94] New translations JabRef_en.properties (Greek) --- src/main/resources/l10n/JabRef_el.properties | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/resources/l10n/JabRef_el.properties b/src/main/resources/l10n/JabRef_el.properties index ccffa7831b9..f6b6e36061d 100644 --- a/src/main/resources/l10n/JabRef_el.properties +++ b/src/main/resources/l10n/JabRef_el.properties @@ -146,7 +146,6 @@ Column\ width=Μήκος στήλης Command\ line\ id=id γραμμής εντολών - Contained\ in=Περιέχεται σε Content=Περιεχόμενο @@ -681,8 +680,6 @@ Open\ file=Άνοιγμα αρχείου - - From 0c36a292502f4d6c00e0cd0be5cd7522897ecabf Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Sat, 17 Feb 2018 07:12:04 +0100 Subject: [PATCH 60/94] New translations JabRef_en.properties (Indonesian) --- src/main/resources/l10n/JabRef_in.properties | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/resources/l10n/JabRef_in.properties b/src/main/resources/l10n/JabRef_in.properties index f6d46c7879d..08fba6bcfa9 100644 --- a/src/main/resources/l10n/JabRef_in.properties +++ b/src/main/resources/l10n/JabRef_in.properties @@ -212,7 +212,6 @@ Column\ width=Lebar kolom Command\ line\ id=id perintah baris - Contained\ in=Terkandung di Content=Isi @@ -1005,9 +1004,7 @@ Resolve\ strings\ for\ all\ fields\ except=Selesaikan masalah string untuk semua Resolve\ strings\ for\ standard\ BibTeX\ fields\ only=Selesaikan masalah string hanya pada bidang BibTeX standar resolved=sudah diselesaikan - Review=Periksa ulang - Review\ changes=Periksa ulang perubahan Right=Kanan From 467593277f865c5e387e57b595f5fae8e569622d Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Sat, 17 Feb 2018 07:12:07 +0100 Subject: [PATCH 61/94] New translations JabRef_en.properties (Italian) --- src/main/resources/l10n/JabRef_it.properties | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/resources/l10n/JabRef_it.properties b/src/main/resources/l10n/JabRef_it.properties index c062730567d..9ea5c66699d 100644 --- a/src/main/resources/l10n/JabRef_it.properties +++ b/src/main/resources/l10n/JabRef_it.properties @@ -211,7 +211,6 @@ Column\ width=Larghezza della colonna Command\ line\ id=Identificativo della riga di comando - Contained\ in=Contenuto in Content=Contenuto @@ -1000,9 +999,7 @@ Resolve\ strings\ for\ all\ fields\ except=Risolve le stringhe per tutti i campi Resolve\ strings\ for\ standard\ BibTeX\ fields\ only=Risolve le stringhe solo per i campi BibTeX standard resolved=risolto - Review=Rivedi - Review\ changes=Rivedi le modifiche Right=Destra From 602c438aa6829780b6d121bf27ca4d7d9769f246 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Sat, 17 Feb 2018 07:12:11 +0100 Subject: [PATCH 62/94] New translations JabRef_en.properties (Vietnamese) --- src/main/resources/l10n/JabRef_vi.properties | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/resources/l10n/JabRef_vi.properties b/src/main/resources/l10n/JabRef_vi.properties index ff713e1db72..9151270ab7a 100644 --- a/src/main/resources/l10n/JabRef_vi.properties +++ b/src/main/resources/l10n/JabRef_vi.properties @@ -208,7 +208,6 @@ Column\ width=Chiều rộng cột Command\ line\ id=Chỉ số (id) của dòng lệnh - Contained\ in=Chứa trong Content=Nội dung @@ -982,9 +981,7 @@ Resolve\ strings\ for\ all\ fields\ except=Giải các chuỗi cho tất cả c Resolve\ strings\ for\ standard\ BibTeX\ fields\ only=Chỉ giải các chuỗi cho các dữ liệu BibTeX resolved=được giải - Review=Xem xét lại - Review\ changes=Xem xét lại các thay đổi Right=Phải From 863813ac15a11d459c5da20b07d6d5cf87c2cf3f Mon Sep 17 00:00:00 2001 From: Linus Dietz Date: Sat, 17 Feb 2018 08:41:54 +0100 Subject: [PATCH 63/94] Move the Review->Comment Migration stuff to the importer package --- .../actions/CheckForNewEntryTypesAction.java | 1 - .../actions/MergeReviewIntoComment.java | 20 ++++++ .../MergeReviewIntoCommentConfirmation.java} | 13 +++- .../importer/actions/OpenDatabaseAction.java | 10 +-- .../MergeReviewIntoCommentMigration.java | 71 +++++++++++++++++++ .../jabref/logic/importer/OpenDatabase.java | 7 +- .../migrations/FileLinksUpgradeWarning.java | 23 +++--- .../migrations/MergeReviewIntoComment.java | 71 ------------------- .../MergeReviewIntoCommentMigrationTest.java} | 12 ++-- 9 files changed, 125 insertions(+), 103 deletions(-) create mode 100644 src/main/java/org/jabref/gui/importer/actions/MergeReviewIntoComment.java rename src/main/java/org/jabref/gui/{dialogs/MergeReviewIntoCommentUIManager.java => importer/actions/MergeReviewIntoCommentConfirmation.java} (80%) create mode 100644 src/main/java/org/jabref/logic/importer/MergeReviewIntoCommentMigration.java delete mode 100644 src/main/java/org/jabref/migrations/MergeReviewIntoComment.java rename src/test/java/org/jabref/{migrations/MergeReviewIntoCommentTest.java => logic/importer/MergeReviewIntoCommentMigrationTest.java} (88%) diff --git a/src/main/java/org/jabref/gui/importer/actions/CheckForNewEntryTypesAction.java b/src/main/java/org/jabref/gui/importer/actions/CheckForNewEntryTypesAction.java index a2506ac13a7..913c8261ea9 100644 --- a/src/main/java/org/jabref/gui/importer/actions/CheckForNewEntryTypesAction.java +++ b/src/main/java/org/jabref/gui/importer/actions/CheckForNewEntryTypesAction.java @@ -37,7 +37,6 @@ public boolean isActionNecessary(ParserResult parserResult) { @Override public void performAction(BasePanel panel, ParserResult parserResult) { - BibDatabaseMode mode = getBibDatabaseModeFromParserResult(parserResult); List typesToStore = determineEntryTypesToSave(panel, getListOfUnknownAndUnequalCustomizations(parserResult), mode); diff --git a/src/main/java/org/jabref/gui/importer/actions/MergeReviewIntoComment.java b/src/main/java/org/jabref/gui/importer/actions/MergeReviewIntoComment.java new file mode 100644 index 00000000000..ec76f5ca3c2 --- /dev/null +++ b/src/main/java/org/jabref/gui/importer/actions/MergeReviewIntoComment.java @@ -0,0 +1,20 @@ +package org.jabref.gui.importer.actions; + +import org.jabref.gui.BasePanel; +import org.jabref.logic.importer.MergeReviewIntoCommentMigration; +import org.jabref.logic.importer.ParserResult; + +public class MergeReviewIntoComment implements GUIPostOpenAction { + + @Override + public boolean isActionNecessary(ParserResult parserResult) { + return !MergeReviewIntoCommentMigration.collectConflicts(parserResult).isEmpty(); + } + + @Override + public void performAction(BasePanel basePanel, ParserResult parserResult) { + if (new MergeReviewIntoCommentConfirmation(basePanel).askUserForMerge(MergeReviewIntoCommentMigration.collectConflicts(parserResult))) { + new MergeReviewIntoCommentMigration().performConflictingMigration(parserResult); + } + } +} diff --git a/src/main/java/org/jabref/gui/dialogs/MergeReviewIntoCommentUIManager.java b/src/main/java/org/jabref/gui/importer/actions/MergeReviewIntoCommentConfirmation.java similarity index 80% rename from src/main/java/org/jabref/gui/dialogs/MergeReviewIntoCommentUIManager.java rename to src/main/java/org/jabref/gui/importer/actions/MergeReviewIntoCommentConfirmation.java index 4e03dad775c..5c422f0f5a1 100644 --- a/src/main/java/org/jabref/gui/dialogs/MergeReviewIntoCommentUIManager.java +++ b/src/main/java/org/jabref/gui/importer/actions/MergeReviewIntoCommentConfirmation.java @@ -1,4 +1,4 @@ -package org.jabref.gui.dialogs; +package org.jabref.gui.importer.actions; import java.util.List; import java.util.Optional; @@ -6,10 +6,17 @@ import javax.swing.JOptionPane; +import org.jabref.gui.BasePanel; import org.jabref.logic.l10n.Localization; import org.jabref.model.entry.BibEntry; -public class MergeReviewIntoCommentUIManager { +public class MergeReviewIntoCommentConfirmation { + + private final BasePanel panel; + + public MergeReviewIntoCommentConfirmation(BasePanel panel) { + this.panel = panel; + } public boolean askUserForMerge(List conflicts) { List bibKeys = conflicts.stream() @@ -19,7 +26,7 @@ public boolean askUserForMerge(List conflicts) { .collect(Collectors.toList()); int answer = JOptionPane.showConfirmDialog( - null, + panel, String.join(",\n", bibKeys) + " " + Localization.lang("has/have both a 'Comment' and a 'Review' field.") + "\n" + Localization.lang("Since the 'Review' field was deprecated in JabRef 4.2, these two fields are about to be merged into the 'Comment' field.") + "\n" + diff --git a/src/main/java/org/jabref/gui/importer/actions/OpenDatabaseAction.java b/src/main/java/org/jabref/gui/importer/actions/OpenDatabaseAction.java index 6a4b0dd6736..502db783fe2 100644 --- a/src/main/java/org/jabref/gui/importer/actions/OpenDatabaseAction.java +++ b/src/main/java/org/jabref/gui/importer/actions/OpenDatabaseAction.java @@ -50,7 +50,6 @@ import org.slf4j.LoggerFactory; // The action concerned with opening an existing database. - public class OpenDatabaseAction extends MnemonicAwareAction { public static final Logger LOGGER = LoggerFactory.getLogger(OpenDatabaseAction.class); @@ -59,11 +58,13 @@ public class OpenDatabaseAction extends MnemonicAwareAction { private static final List POST_OPEN_ACTIONS = new ArrayList<>(); static { - // Add the action for checking for new custom entry types loaded from the BIB file: + // Warning for migrating the Review into the Comment field + POST_OPEN_ACTIONS.add(new MergeReviewIntoComment()); + // Check for new custom entry types loaded from the BIB file: POST_OPEN_ACTIONS.add(new CheckForNewEntryTypesAction()); - // Add the action for the new external file handling system in version 2.3: + // External file handling system in version 2.3: POST_OPEN_ACTIONS.add(new FileLinksUpgradeWarning()); - // Add the action for warning about and handling duplicate BibTeX keys: + // Warning about and handling duplicate BibTeX keys: POST_OPEN_ACTIONS.add(new HandleDuplicateWarnings()); } @@ -99,7 +100,6 @@ public void actionPerformed(ActionEvent e) { List filesToOpen = new ArrayList<>(); if (showDialog) { - DialogService ds = new FXDialogService(); FileDialogConfiguration fileDialogConfiguration = new FileDialogConfiguration.Builder() .addExtensionFilter(FileType.BIBTEX_DB) diff --git a/src/main/java/org/jabref/logic/importer/MergeReviewIntoCommentMigration.java b/src/main/java/org/jabref/logic/importer/MergeReviewIntoCommentMigration.java new file mode 100644 index 00000000000..f98efe55df1 --- /dev/null +++ b/src/main/java/org/jabref/logic/importer/MergeReviewIntoCommentMigration.java @@ -0,0 +1,71 @@ +package org.jabref.logic.importer; + +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +import org.jabref.logic.l10n.Localization; +import org.jabref.migrations.PostOpenMigration; +import org.jabref.model.entry.BibEntry; +import org.jabref.model.entry.FieldName; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class MergeReviewIntoCommentMigration implements PostOpenMigration { + public static final Logger LOGGER = LoggerFactory.getLogger(MergeReviewIntoCommentMigration.class); + + @Override + public void performMigration(ParserResult parserResult) { + /* This migration only handles the non-conflicting entries. + * For the other see this.performConflictingMigration(). + */ + List entries = Objects.requireNonNull(parserResult).getDatabase().getEntries(); + + entries.stream() + .filter(MergeReviewIntoCommentMigration::hasReviewField) + .filter(entry -> !MergeReviewIntoCommentMigration.hasCommentField(entry)) + .forEach(entry -> migrate(entry, parserResult)); + } + + public static List collectConflicts(ParserResult parserResult) { + List entries = Objects.requireNonNull(parserResult).getDatabase().getEntries(); + + return entries.stream() + .filter(MergeReviewIntoCommentMigration::hasReviewField) + .filter(MergeReviewIntoCommentMigration::hasCommentField) + .collect(Collectors.toList()); + } + + public void performConflictingMigration(ParserResult parserResult) { + collectConflicts(parserResult).forEach(entry -> migrate(entry, parserResult)); + } + + private String mergeCommentFieldIfPresent(BibEntry entry, String review) { + if (entry.getField(FieldName.COMMENT).isPresent()) { + LOGGER.info(String.format("Both Comment and Review fields are present in %s! Merging them into the comment field.", entry.getAuthorTitleYear(150))); + return String.format("%s\n%s:\n%s", entry.getField(FieldName.COMMENT).get().trim(), Localization.lang("Review"), review.trim()); + } + return review; + } + + private static boolean hasCommentField(BibEntry entry) { + return entry.getField(FieldName.COMMENT).isPresent(); + } + + private static boolean hasReviewField(BibEntry entry) { + return entry.getField(FieldName.REVIEW).isPresent(); + } + + private void migrate(BibEntry entry, ParserResult parserResult) { + if (hasReviewField(entry)) { + updateFields(entry, mergeCommentFieldIfPresent(entry, entry.getField(FieldName.REVIEW).get())); + parserResult.wasChangedOnMigration(); + } + } + + private void updateFields(BibEntry entry, String review) { + entry.setField(FieldName.COMMENT, review); + entry.clearField(FieldName.REVIEW); + } +} diff --git a/src/main/java/org/jabref/logic/importer/OpenDatabase.java b/src/main/java/org/jabref/logic/importer/OpenDatabase.java index 1c3197e0e7b..7d1be8835b1 100644 --- a/src/main/java/org/jabref/logic/importer/OpenDatabase.java +++ b/src/main/java/org/jabref/logic/importer/OpenDatabase.java @@ -10,7 +10,6 @@ import org.jabref.logic.specialfields.SpecialFieldsUtils; import org.jabref.logic.util.io.FileBasedLock; import org.jabref.migrations.ConvertLegacyExplicitGroups; -import org.jabref.migrations.MergeReviewIntoComment; import org.jabref.migrations.PostOpenMigration; import org.jabref.model.entry.BibEntry; import org.jabref.model.util.FileUpdateMonitor; @@ -29,7 +28,6 @@ private OpenDatabase() { * Load database (bib-file) * * @param name Name of the BIB-file to open - * @param fileMonitor * @return ParserResult which never is null */ public static ParserResult loadDatabase(String name, ImportFormatPreferences importFormatPreferences, FileUpdateMonitor fileMonitor) { @@ -89,7 +87,10 @@ public static ParserResult loadDatabase(File fileToOpen, ImportFormatPreferences private static void performLoadDatabaseMigrations(ParserResult parserResult) { - List postOpenMigrations = Arrays.asList(new ConvertLegacyExplicitGroups(), new MergeReviewIntoComment()); + List postOpenMigrations = Arrays.asList( + new ConvertLegacyExplicitGroups(), + new MergeReviewIntoCommentMigration() + ); for (PostOpenMigration migration : postOpenMigrations) { migration.performMigration(parserResult); diff --git a/src/main/java/org/jabref/migrations/FileLinksUpgradeWarning.java b/src/main/java/org/jabref/migrations/FileLinksUpgradeWarning.java index 410deea49fe..563046dd851 100644 --- a/src/main/java/org/jabref/migrations/FileLinksUpgradeWarning.java +++ b/src/main/java/org/jabref/migrations/FileLinksUpgradeWarning.java @@ -43,7 +43,7 @@ */ public class FileLinksUpgradeWarning implements GUIPostOpenAction { - private static final String[] FIELDS_TO_LOOK_FOR = new String[] {FieldName.PDF, FieldName.PS}; + private static final String[] FIELDS_TO_LOOK_FOR = new String[]{FieldName.PDF, FieldName.PS}; private boolean offerChangeSettings; @@ -56,7 +56,6 @@ public class FileLinksUpgradeWarning implements GUIPostOpenAction { * GUIGlobals.FILE_FIELD. * * @param database The database to modify. - * @param fields The fields to find links in. * @return A CompoundEdit specifying the undo operation for the whole operation. */ private static NamedCompound upgradePdfPsToFile(BibDatabase database) { @@ -78,7 +77,7 @@ private static NamedCompound upgradePdfPsToFile(BibDatabase database) { /** * This method should be performed if the major/minor versions recorded in the ParserResult * are less than or equal to 2.2. - * @param pr + * * @return true if the file was written by a jabref version <=2.2 */ @Override @@ -91,18 +90,16 @@ public boolean isActionNecessary(ParserResult pr) { // If the "file" directory is not set, offer to migrate pdf/ps dir: offerSetFileDir = !Globals.prefs.hasKey(FieldName.FILE + FileDirectoryPreferences.DIR_SUFFIX) && (Globals.prefs.hasKey(FieldName.PDF + FileDirectoryPreferences.DIR_SUFFIX) - || Globals.prefs.hasKey(FieldName.PS + FileDirectoryPreferences.DIR_SUFFIX)); + || Globals.prefs.hasKey(FieldName.PS + FileDirectoryPreferences.DIR_SUFFIX)); // First check if this warning is disabled: return Globals.prefs.getBoolean(JabRefPreferences.SHOW_FILE_LINKS_UPGRADE_WARNING) && isThereSomethingToBeDone(); } - /** + /* * This method presents a dialog box explaining and offering to make the * changes. If the user confirms, the changes are performed. - * @param panel - * @param parserResult */ @Override public void performAction(BasePanel panel, ParserResult parserResult) { @@ -130,7 +127,7 @@ public void performAction(BasePanel panel, ParserResult parserResult) { int row = 1; formBuilder.add(new JLabel("" + Localization.lang("This library uses outdated file links.") + "

" + Localization - .lang("JabRef no longer supports 'ps' or 'pdf' fields.
File links are now stored in the 'file' field and files are stored in an external file directory.
To make use of this feature, JabRef needs to upgrade file links.

") + .lang("JabRef no longer supports 'ps' or 'pdf' fields.
File links are now stored in the 'file' field and files are stored in an external file directory.
To make use of this feature, JabRef needs to upgrade file links.

") + "

" + Localization.lang("Do you want JabRef to do the following operations?") + "")).xy(1, row); @@ -191,10 +188,11 @@ private boolean isThereSomethingToBeDone() { /** * Check the database to find out whether any of a set of fields are used * for any of the entries. + * * @param database The BIB database. - * @param fields The set of fields to look for. + * @param fields The set of fields to look for. * @return true if at least one of the given fields is set in at least one entry, - * false otherwise. + * false otherwise. */ private boolean linksFound(BibDatabase database, String[] fields) { for (BibEntry entry : database.getEntries()) { @@ -209,12 +207,11 @@ private boolean linksFound(BibDatabase database, String[] fields) { /** * This method performs the actual changes. - * @param panel - * @param pr + * * @param fileDir The path to the file directory to set, or null if it should not be set. */ private void makeChanges(BasePanel panel, ParserResult pr, boolean upgradePrefs, - boolean upgradeDatabase, String fileDir) { + boolean upgradeDatabase, String fileDir) { if (upgradeDatabase) { // Update file links links in the database: diff --git a/src/main/java/org/jabref/migrations/MergeReviewIntoComment.java b/src/main/java/org/jabref/migrations/MergeReviewIntoComment.java deleted file mode 100644 index 76280caa24a..00000000000 --- a/src/main/java/org/jabref/migrations/MergeReviewIntoComment.java +++ /dev/null @@ -1,71 +0,0 @@ -package org.jabref.migrations; - -import java.util.List; -import java.util.Objects; -import java.util.stream.Collectors; - -import javafx.collections.ObservableList; - -import org.jabref.gui.dialogs.MergeReviewIntoCommentUIManager; -import org.jabref.logic.importer.ParserResult; -import org.jabref.logic.l10n.Localization; -import org.jabref.model.entry.BibEntry; -import org.jabref.model.entry.FieldName; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class MergeReviewIntoComment implements PostOpenMigration { - public static final Logger LOGGER = LoggerFactory.getLogger(MergeReviewIntoComment.class); - - @Override - public void performMigration(ParserResult parserResult) { - ObservableList entries = Objects.requireNonNull(parserResult).getDatabase().getEntries(); - - // migrate non-conflicting entries first - entries.stream() - .filter(this::hasReviewField) - .filter(entry -> !this.hasCommentField(entry)) - .forEach(entry -> migrate(entry, parserResult)); - - // determine conflicts - List conflicts = entries.stream() - .filter(this::hasReviewField) - .filter(this::hasCommentField) - .collect(Collectors.toList()); - - // resolve conflicts if users agrees - if (!conflicts.isEmpty() && new MergeReviewIntoCommentUIManager().askUserForMerge(conflicts)) { - conflicts.stream() - .filter(this::hasReviewField) - .forEach(entry -> migrate(entry, parserResult)); - } - } - - private String mergeCommentFieldIfPresent(BibEntry entry, String review) { - if (entry.getField(FieldName.COMMENT).isPresent()) { - LOGGER.info(String.format("Both Comment and Review fields are present in %s! Merging them into the comment field.", entry.getAuthorTitleYear(150))); - return String.format("%s\n%s:\n%s", entry.getField(FieldName.COMMENT).get().trim(), Localization.lang("Review"), review.trim()); - } - return review; - } - - private boolean hasCommentField(BibEntry entry) { - return entry.getField(FieldName.COMMENT).isPresent(); - } - - private boolean hasReviewField(BibEntry entry) { - return entry.getField(FieldName.REVIEW).isPresent(); - } - - private void migrate(BibEntry entry, ParserResult parserResult) { - // this method may only be called if the review field is present - updateFields(entry, mergeCommentFieldIfPresent(entry, entry.getField(FieldName.REVIEW).get())); - parserResult.wasChangedOnMigration(); - } - - private void updateFields(BibEntry entry, String review) { - entry.setField(FieldName.COMMENT, review); - entry.clearField(FieldName.REVIEW); - } -} diff --git a/src/test/java/org/jabref/migrations/MergeReviewIntoCommentTest.java b/src/test/java/org/jabref/logic/importer/MergeReviewIntoCommentMigrationTest.java similarity index 88% rename from src/test/java/org/jabref/migrations/MergeReviewIntoCommentTest.java rename to src/test/java/org/jabref/logic/importer/MergeReviewIntoCommentMigrationTest.java index b142e86a46c..b84d22d2ea4 100644 --- a/src/test/java/org/jabref/migrations/MergeReviewIntoCommentTest.java +++ b/src/test/java/org/jabref/logic/importer/MergeReviewIntoCommentMigrationTest.java @@ -1,8 +1,7 @@ -package org.jabref.migrations; +package org.jabref.logic.importer; import java.util.Collections; -import org.jabref.logic.importer.ParserResult; import org.jabref.logic.l10n.Localization; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.FieldName; @@ -13,13 +12,12 @@ import static org.junit.jupiter.api.Assertions.assertEquals; -class MergeReviewIntoCommentTest { - - private MergeReviewIntoComment action; +class MergeReviewIntoCommentMigrationTest { + private MergeReviewIntoCommentMigration action; @BeforeEach public void setUp() { - action = new MergeReviewIntoComment(); + action = new MergeReviewIntoCommentMigration(); } @Test @@ -59,7 +57,7 @@ public void commentField() { @Test - @Disabled("Re-enable if the MergeReviewIntoComment.mergeCommentFieldIfPresent() does not block and wait for user input.") + @Disabled("Re-enable if the MergeReviewIntoCommentMigration.mergeCommentFieldIfPresent() does not block and wait for user input.") public void reviewAndCommentField() { BibEntry actualEntry = createMinimalBibEntry(); actualEntry.setField(FieldName.REVIEW, "My Review"); From a25040af0b0147ae064ffdce2fd7bf6ca4c21bd8 Mon Sep 17 00:00:00 2001 From: Linus Dietz Date: Sat, 17 Feb 2018 08:43:05 +0100 Subject: [PATCH 64/94] use joining collector --- .../actions/MergeReviewIntoCommentConfirmation.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/jabref/gui/importer/actions/MergeReviewIntoCommentConfirmation.java b/src/main/java/org/jabref/gui/importer/actions/MergeReviewIntoCommentConfirmation.java index 5c422f0f5a1..f4746fbe94b 100644 --- a/src/main/java/org/jabref/gui/importer/actions/MergeReviewIntoCommentConfirmation.java +++ b/src/main/java/org/jabref/gui/importer/actions/MergeReviewIntoCommentConfirmation.java @@ -19,15 +19,15 @@ public MergeReviewIntoCommentConfirmation(BasePanel panel) { } public boolean askUserForMerge(List conflicts) { - List bibKeys = conflicts.stream() + String bibKeys = conflicts.stream() .map(BibEntry::getCiteKeyOptional) .filter(Optional::isPresent) .map(Optional::get) - .collect(Collectors.toList()); + .collect(Collectors.joining(",\n")); int answer = JOptionPane.showConfirmDialog( panel, - String.join(",\n", bibKeys) + " " + + bibKeys + " " + Localization.lang("has/have both a 'Comment' and a 'Review' field.") + "\n" + Localization.lang("Since the 'Review' field was deprecated in JabRef 4.2, these two fields are about to be merged into the 'Comment' field.") + "\n" + Localization.lang("The conflicting fields of these entries will be merged into the 'Comment' field."), From 9e86f5b2a1797b8dee66522375377ed7155dccfd Mon Sep 17 00:00:00 2001 From: Linus Dietz Date: Sat, 17 Feb 2018 09:23:13 +0100 Subject: [PATCH 65/94] Move all database migrations into the org.jabref.logic.importer.migrations package --- .../actions/MergeReviewIntoComment.java | 9 ++++-- .../importer/actions/OpenDatabaseAction.java | 31 +++++++++---------- .../jabref/logic/importer/OpenDatabase.java | 8 ++--- .../migrations/FileLinksUpgradeWarning.java | 2 +- .../MergeReviewIntoCommentMigration.java | 12 ++++--- .../MergeReviewIntoCommentMigrationTest.java | 3 +- 6 files changed, 34 insertions(+), 31 deletions(-) rename src/main/java/org/jabref/{ => logic/importer}/migrations/FileLinksUpgradeWarning.java (99%) rename src/main/java/org/jabref/logic/importer/{ => migrations}/MergeReviewIntoCommentMigration.java (88%) rename src/test/java/org/jabref/logic/importer/{ => migrations}/MergeReviewIntoCommentMigrationTest.java (96%) diff --git a/src/main/java/org/jabref/gui/importer/actions/MergeReviewIntoComment.java b/src/main/java/org/jabref/gui/importer/actions/MergeReviewIntoComment.java index ec76f5ca3c2..e51e0156052 100644 --- a/src/main/java/org/jabref/gui/importer/actions/MergeReviewIntoComment.java +++ b/src/main/java/org/jabref/gui/importer/actions/MergeReviewIntoComment.java @@ -1,20 +1,23 @@ package org.jabref.gui.importer.actions; import org.jabref.gui.BasePanel; -import org.jabref.logic.importer.MergeReviewIntoCommentMigration; import org.jabref.logic.importer.ParserResult; +import org.jabref.logic.importer.migrations.MergeReviewIntoCommentMigration; public class MergeReviewIntoComment implements GUIPostOpenAction { @Override public boolean isActionNecessary(ParserResult parserResult) { - return !MergeReviewIntoCommentMigration.collectConflicts(parserResult).isEmpty(); + return MergeReviewIntoCommentMigration.needsMigration(parserResult); } @Override public void performAction(BasePanel basePanel, ParserResult parserResult) { + MergeReviewIntoCommentMigration migration = new MergeReviewIntoCommentMigration(); + + migration.performMigration(parserResult); if (new MergeReviewIntoCommentConfirmation(basePanel).askUserForMerge(MergeReviewIntoCommentMigration.collectConflicts(parserResult))) { - new MergeReviewIntoCommentMigration().performConflictingMigration(parserResult); + migration.performConflictingMigration(parserResult); } } } diff --git a/src/main/java/org/jabref/gui/importer/actions/OpenDatabaseAction.java b/src/main/java/org/jabref/gui/importer/actions/OpenDatabaseAction.java index 502db783fe2..71c0ee37869 100644 --- a/src/main/java/org/jabref/gui/importer/actions/OpenDatabaseAction.java +++ b/src/main/java/org/jabref/gui/importer/actions/OpenDatabaseAction.java @@ -7,6 +7,7 @@ import java.nio.file.attribute.FileTime; import java.sql.SQLException; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.Iterator; import java.util.List; @@ -35,12 +36,12 @@ import org.jabref.logic.autosaveandbackup.BackupManager; import org.jabref.logic.importer.OpenDatabase; import org.jabref.logic.importer.ParserResult; +import org.jabref.logic.importer.migrations.FileLinksUpgradeWarning; import org.jabref.logic.l10n.Localization; import org.jabref.logic.shared.exception.InvalidDBMSConnectionPropertiesException; import org.jabref.logic.shared.exception.NotASharedDatabaseException; import org.jabref.logic.util.FileType; import org.jabref.logic.util.io.FileBasedLock; -import org.jabref.migrations.FileLinksUpgradeWarning; import org.jabref.model.database.BibDatabase; import org.jabref.model.database.shared.DatabaseNotSupportedException; import org.jabref.model.strings.StringUtil; @@ -55,18 +56,18 @@ public class OpenDatabaseAction extends MnemonicAwareAction { public static final Logger LOGGER = LoggerFactory.getLogger(OpenDatabaseAction.class); // List of actions that may need to be called after opening the file. Such as // upgrade actions etc. that may depend on the JabRef version that wrote the file: - private static final List POST_OPEN_ACTIONS = new ArrayList<>(); - - static { - // Warning for migrating the Review into the Comment field - POST_OPEN_ACTIONS.add(new MergeReviewIntoComment()); - // Check for new custom entry types loaded from the BIB file: - POST_OPEN_ACTIONS.add(new CheckForNewEntryTypesAction()); - // External file handling system in version 2.3: - POST_OPEN_ACTIONS.add(new FileLinksUpgradeWarning()); - // Warning about and handling duplicate BibTeX keys: - POST_OPEN_ACTIONS.add(new HandleDuplicateWarnings()); - } + private static final List POST_OPEN_ACTIONS = Arrays.asList( + // Migrations: + // Warning for migrating the Review into the Comment field + new MergeReviewIntoComment(), + // External file handling system in version 2.3: + new FileLinksUpgradeWarning(), + + // Check for new custom entry types loaded from the BIB file: + new CheckForNewEntryTypesAction(), + // Warning about and handling duplicate BibTeX keys: + new HandleDuplicateWarnings()); + private final boolean showDialog; private final JabRefFrame frame; @@ -146,7 +147,7 @@ public void openFiles(List filesToOpen, boolean raisePanel) { int removed = 0; // Check if any of the files are already open: - for (Iterator iterator = filesToOpen.iterator(); iterator.hasNext();) { + for (Iterator iterator = filesToOpen.iterator(); iterator.hasNext(); ) { Path file = iterator.next(); for (int i = 0; i < frame.getTabbedPane().getTabCount(); i++) { BasePanel basePanel = frame.getBasePanelAt(i); @@ -224,7 +225,6 @@ private void openTheFile(Path file, boolean raisePanel) { Localization.lang("Error"), JOptionPane.ERROR_MESSAGE); return; } - } if (BackupManager.checkForBackupFile(fileToLoad)) { @@ -284,5 +284,4 @@ private BasePanel addNewDatabase(ParserResult result, final Path file, boolean r return basePanel; } - } diff --git a/src/main/java/org/jabref/logic/importer/OpenDatabase.java b/src/main/java/org/jabref/logic/importer/OpenDatabase.java index 7d1be8835b1..6b5b451eaca 100644 --- a/src/main/java/org/jabref/logic/importer/OpenDatabase.java +++ b/src/main/java/org/jabref/logic/importer/OpenDatabase.java @@ -2,7 +2,7 @@ import java.io.File; import java.io.IOException; -import java.util.Arrays; +import java.util.Collections; import java.util.List; import org.jabref.logic.importer.fileformat.BibtexImporter; @@ -86,11 +86,7 @@ public static ParserResult loadDatabase(File fileToOpen, ImportFormatPreferences } private static void performLoadDatabaseMigrations(ParserResult parserResult) { - - List postOpenMigrations = Arrays.asList( - new ConvertLegacyExplicitGroups(), - new MergeReviewIntoCommentMigration() - ); + List postOpenMigrations = Collections.singletonList(new ConvertLegacyExplicitGroups()); for (PostOpenMigration migration : postOpenMigrations) { migration.performMigration(parserResult); diff --git a/src/main/java/org/jabref/migrations/FileLinksUpgradeWarning.java b/src/main/java/org/jabref/logic/importer/migrations/FileLinksUpgradeWarning.java similarity index 99% rename from src/main/java/org/jabref/migrations/FileLinksUpgradeWarning.java rename to src/main/java/org/jabref/logic/importer/migrations/FileLinksUpgradeWarning.java index 563046dd851..f8b1d66f4f5 100644 --- a/src/main/java/org/jabref/migrations/FileLinksUpgradeWarning.java +++ b/src/main/java/org/jabref/logic/importer/migrations/FileLinksUpgradeWarning.java @@ -1,4 +1,4 @@ -package org.jabref.migrations; +package org.jabref.logic.importer.migrations; import java.util.List; diff --git a/src/main/java/org/jabref/logic/importer/MergeReviewIntoCommentMigration.java b/src/main/java/org/jabref/logic/importer/migrations/MergeReviewIntoCommentMigration.java similarity index 88% rename from src/main/java/org/jabref/logic/importer/MergeReviewIntoCommentMigration.java rename to src/main/java/org/jabref/logic/importer/migrations/MergeReviewIntoCommentMigration.java index f98efe55df1..e60e88a2ec1 100644 --- a/src/main/java/org/jabref/logic/importer/MergeReviewIntoCommentMigration.java +++ b/src/main/java/org/jabref/logic/importer/migrations/MergeReviewIntoCommentMigration.java @@ -1,21 +1,25 @@ -package org.jabref.logic.importer; +package org.jabref.logic.importer.migrations; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; +import org.jabref.logic.importer.ParserResult; import org.jabref.logic.l10n.Localization; -import org.jabref.migrations.PostOpenMigration; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.FieldName; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class MergeReviewIntoCommentMigration implements PostOpenMigration { +public class MergeReviewIntoCommentMigration { public static final Logger LOGGER = LoggerFactory.getLogger(MergeReviewIntoCommentMigration.class); - @Override + public static boolean needsMigration(ParserResult parserResult) { + return parserResult.getDatabase().getEntries().stream() + .anyMatch(bibEntry -> bibEntry.getField(FieldName.REVIEW).isPresent()); + } + public void performMigration(ParserResult parserResult) { /* This migration only handles the non-conflicting entries. * For the other see this.performConflictingMigration(). diff --git a/src/test/java/org/jabref/logic/importer/MergeReviewIntoCommentMigrationTest.java b/src/test/java/org/jabref/logic/importer/migrations/MergeReviewIntoCommentMigrationTest.java similarity index 96% rename from src/test/java/org/jabref/logic/importer/MergeReviewIntoCommentMigrationTest.java rename to src/test/java/org/jabref/logic/importer/migrations/MergeReviewIntoCommentMigrationTest.java index b84d22d2ea4..5bd2d2051dd 100644 --- a/src/test/java/org/jabref/logic/importer/MergeReviewIntoCommentMigrationTest.java +++ b/src/test/java/org/jabref/logic/importer/migrations/MergeReviewIntoCommentMigrationTest.java @@ -1,7 +1,8 @@ -package org.jabref.logic.importer; +package org.jabref.logic.importer.migrations; import java.util.Collections; +import org.jabref.logic.importer.ParserResult; import org.jabref.logic.l10n.Localization; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.FieldName; From e02d63381b99aa9fb070d14914d106f35c65e31d Mon Sep 17 00:00:00 2001 From: Linus Dietz Date: Sat, 17 Feb 2018 21:56:03 +0100 Subject: [PATCH 66/94] incorporate feedback --- .../org/jabref/gui/importer/actions/MergeReviewIntoComment.java | 2 +- .../org/jabref/gui/importer/actions/OpenDatabaseAction.java | 2 +- .../migrations/MergeReviewIntoCommentMigration.java | 2 +- .../importer => }/migrations/FileLinksUpgradeWarning.java | 2 +- .../migrations/MergeReviewIntoCommentMigrationTest.java | 1 + 5 files changed, 5 insertions(+), 4 deletions(-) rename src/main/java/org/jabref/logic/{importer => }/migrations/MergeReviewIntoCommentMigration.java (98%) rename src/main/java/org/jabref/{logic/importer => }/migrations/FileLinksUpgradeWarning.java (99%) diff --git a/src/main/java/org/jabref/gui/importer/actions/MergeReviewIntoComment.java b/src/main/java/org/jabref/gui/importer/actions/MergeReviewIntoComment.java index e51e0156052..61fd6fb028b 100644 --- a/src/main/java/org/jabref/gui/importer/actions/MergeReviewIntoComment.java +++ b/src/main/java/org/jabref/gui/importer/actions/MergeReviewIntoComment.java @@ -2,7 +2,7 @@ import org.jabref.gui.BasePanel; import org.jabref.logic.importer.ParserResult; -import org.jabref.logic.importer.migrations.MergeReviewIntoCommentMigration; +import org.jabref.logic.migrations.MergeReviewIntoCommentMigration; public class MergeReviewIntoComment implements GUIPostOpenAction { diff --git a/src/main/java/org/jabref/gui/importer/actions/OpenDatabaseAction.java b/src/main/java/org/jabref/gui/importer/actions/OpenDatabaseAction.java index 71c0ee37869..d0395b7d626 100644 --- a/src/main/java/org/jabref/gui/importer/actions/OpenDatabaseAction.java +++ b/src/main/java/org/jabref/gui/importer/actions/OpenDatabaseAction.java @@ -36,12 +36,12 @@ import org.jabref.logic.autosaveandbackup.BackupManager; import org.jabref.logic.importer.OpenDatabase; import org.jabref.logic.importer.ParserResult; -import org.jabref.logic.importer.migrations.FileLinksUpgradeWarning; import org.jabref.logic.l10n.Localization; import org.jabref.logic.shared.exception.InvalidDBMSConnectionPropertiesException; import org.jabref.logic.shared.exception.NotASharedDatabaseException; import org.jabref.logic.util.FileType; import org.jabref.logic.util.io.FileBasedLock; +import org.jabref.migrations.FileLinksUpgradeWarning; import org.jabref.model.database.BibDatabase; import org.jabref.model.database.shared.DatabaseNotSupportedException; import org.jabref.model.strings.StringUtil; diff --git a/src/main/java/org/jabref/logic/importer/migrations/MergeReviewIntoCommentMigration.java b/src/main/java/org/jabref/logic/migrations/MergeReviewIntoCommentMigration.java similarity index 98% rename from src/main/java/org/jabref/logic/importer/migrations/MergeReviewIntoCommentMigration.java rename to src/main/java/org/jabref/logic/migrations/MergeReviewIntoCommentMigration.java index e60e88a2ec1..770abb26ffc 100644 --- a/src/main/java/org/jabref/logic/importer/migrations/MergeReviewIntoCommentMigration.java +++ b/src/main/java/org/jabref/logic/migrations/MergeReviewIntoCommentMigration.java @@ -1,4 +1,4 @@ -package org.jabref.logic.importer.migrations; +package org.jabref.logic.migrations; import java.util.List; import java.util.Objects; diff --git a/src/main/java/org/jabref/logic/importer/migrations/FileLinksUpgradeWarning.java b/src/main/java/org/jabref/migrations/FileLinksUpgradeWarning.java similarity index 99% rename from src/main/java/org/jabref/logic/importer/migrations/FileLinksUpgradeWarning.java rename to src/main/java/org/jabref/migrations/FileLinksUpgradeWarning.java index f8b1d66f4f5..563046dd851 100644 --- a/src/main/java/org/jabref/logic/importer/migrations/FileLinksUpgradeWarning.java +++ b/src/main/java/org/jabref/migrations/FileLinksUpgradeWarning.java @@ -1,4 +1,4 @@ -package org.jabref.logic.importer.migrations; +package org.jabref.migrations; import java.util.List; diff --git a/src/test/java/org/jabref/logic/importer/migrations/MergeReviewIntoCommentMigrationTest.java b/src/test/java/org/jabref/logic/importer/migrations/MergeReviewIntoCommentMigrationTest.java index 5bd2d2051dd..8cc331f44ea 100644 --- a/src/test/java/org/jabref/logic/importer/migrations/MergeReviewIntoCommentMigrationTest.java +++ b/src/test/java/org/jabref/logic/importer/migrations/MergeReviewIntoCommentMigrationTest.java @@ -4,6 +4,7 @@ import org.jabref.logic.importer.ParserResult; import org.jabref.logic.l10n.Localization; +import org.jabref.logic.migrations.MergeReviewIntoCommentMigration; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.FieldName; From 01d3d4b95b9295e681da5e20f0b0c7c3d07c5e22 Mon Sep 17 00:00:00 2001 From: Siedlerchr Date: Sun, 18 Feb 2018 00:34:00 +0100 Subject: [PATCH 67/94] add hints for commit message --- CONTRIBUTING.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 96a0a9e217d..80c012f83b1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -48,6 +48,8 @@ Your contribution is considered being made under [MIT license](https://tldrlegal ### Write a good commit message See [good commit message] or [commit guidelines section of Pro Git]. +The first line of your commit message is automatically taken as title for the pull-request. +All other lines make up the body of the pull request. Add the words `fixes #xxx` to your PR to auto-close the corresponding issue. ### Test your code From 45d31b3bf321d1444cb61841870acb9d74656819 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Sun, 18 Feb 2018 17:33:35 +0100 Subject: [PATCH 68/94] New translations JabRef_en.properties (Japanese) --- src/main/resources/l10n/JabRef_ja.properties | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/main/resources/l10n/JabRef_ja.properties b/src/main/resources/l10n/JabRef_ja.properties index e601bcd5e13..5e59bf43026 100644 --- a/src/main/resources/l10n/JabRef_ja.properties +++ b/src/main/resources/l10n/JabRef_ja.properties @@ -149,6 +149,7 @@ Broken\ link=壊れたリンク Browse=一覧 by=置換文字列 +The\ conflicting\ fields\ of\ these\ entries\ will\ be\ merged\ into\ the\ 'Comment'\ field.=これらの項目で衝突の発生しているフィールドは,マージされて「コメント」フィールドに置かれます. Cancel=取消 @@ -211,6 +212,7 @@ Color\ for\ marking\ incomplete\ entries=不完全な項目を標識するのに Column\ width=列幅 Command\ line\ id=コマンドラインID +Comments=コメント Contained\ in=所在 @@ -386,6 +388,7 @@ Edit\ entry=項目を編集 Save\ file=ファイルリンクを編集 Edit\ file\ type=ファイル型を編集 +Add\ group=グループを追加 Edit\ group=グループを編集 @@ -559,6 +562,7 @@ Get\ fulltext=フルテキストを得る Gray\ out\ non-hits=合致しないものを淡色化 Groups=グループ +has/have\ both\ a\ 'Comment'\ and\ a\ 'Review'\ field.=には「Comment」フィールドと「Review」フィールドの両方があります. Have\ you\ chosen\ the\ correct\ package\ path?=正しいパッケージパスを選択しましたか? @@ -993,6 +997,8 @@ Replace\ string=文字列の置換 Replace\ with=置換文字列 +Replace\ Unicode\ ligatures=Unicode合字を置換 +Replaces\ Unicode\ ligatures\ with\ their\ expanded\ form=Unicode合字を分離形で置換 Replaced=置換しました @@ -1006,6 +1012,7 @@ Resolve\ strings\ for\ standard\ BibTeX\ fields\ only=文字列をBibTeX標準 resolved=解消しました Review=論評 Review\ changes=変更を検査する +Review\ Field\ Migration=Reviewフィールドの取り込み Right=右側 @@ -1095,6 +1102,7 @@ Show\ required\ fields=必須フィールドを表示 Show\ URL/DOI\ column=URL/DOI列を表示 +Show\ validation\ messages=検証メッセージを表示 Simple\ HTML=単純なHTML From b88ce0cad2aa3c15db8fac12bd90a39468b43e15 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Sun, 18 Feb 2018 17:42:24 +0100 Subject: [PATCH 69/94] New translations JabRef_en.properties (Japanese) --- src/main/resources/l10n/JabRef_ja.properties | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/resources/l10n/JabRef_ja.properties b/src/main/resources/l10n/JabRef_ja.properties index 5e59bf43026..66f6e627da2 100644 --- a/src/main/resources/l10n/JabRef_ja.properties +++ b/src/main/resources/l10n/JabRef_ja.properties @@ -1105,6 +1105,7 @@ Show\ URL/DOI\ column=URL/DOI列を表示 Show\ validation\ messages=検証メッセージを表示 Simple\ HTML=単純なHTML +Since\ the\ 'Review'\ field\ was\ deprecated\ in\ JabRef\ 4.2,\ these\ two\ fields\ are\ about\ to\ be\ merged\ into\ the\ 'Comment'\ field.=「Review」フィールドはJabRef 4.2で廃止されましたので,これら2つのフィールドは「Comment」フィールドにマージされます. Size=サイズ @@ -1738,6 +1739,7 @@ Unmarked\ all\ entries=全項目の標識を外しました Unable\ to\ find\ the\ requested\ look\ and\ feel\ and\ thus\ the\ default\ one\ is\ used.=要求のあった操作性設定を見つけることができなかったので,既定値を使用します. Opens\ JabRef's\ GitHub\ page=JabRefのGitHubページを開きます +Opens\ JabRef's\ Twitter\ page=JabRefのTwitterページを開きます Opens\ JabRef's\ Facebook\ page=JabRefのFacebookページを開きます Opens\ JabRef's\ blog=JabRefのブログを開きます Opens\ JabRef's\ website=JabRefのウェブサイトを開きます @@ -1881,6 +1883,7 @@ value=値 Show\ preferences=設定を表示 Save\ actions=保存時動作 Enable\ save\ actions=保存時動作を有効化 +Convert\ to\ BibTeX\ format\ (for\ example,\ move\ the\ value\ of\ the\ 'journaltitle'\ field\ to\ 'journal')=BibTeX形式に変換 (「journaltitle」フィールドの値を「journal」に移行するなど) Other\ fields=他のフィールド Show\ remaining\ fields=その他のフィールドを表示 @@ -2342,4 +2345,7 @@ Invalid\ identifier\:\ '%0'.=「%0」は識別子として無効です. This\ paper\ has\ been\ withdrawn.=この論文は撤回されました. Finished\ writing\ XMP-metadata.=XMPメタデータを書き終えました. empty\ BibTeX\ key=空のBibTeX鍵 +Your\ Java\ Runtime\ Environment\ is\ located\ at\ %0.=お使いのJava Runtime Environmentは%0にあります. +Aux\ file=auxファイル +Group\ containing\ entries\ cited\ in\ a\ given\ TeX\ file=特定のTeXファイルでの引用項目を集めたグループ From 2b8e49cbbdf4b5f9fda529451ccc128a06d3c0bf Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Mon, 19 Feb 2018 08:41:13 +0100 Subject: [PATCH 70/94] New translations JabRef_en.properties (French) --- src/main/resources/l10n/JabRef_fr.properties | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/resources/l10n/JabRef_fr.properties b/src/main/resources/l10n/JabRef_fr.properties index 8170ee3049a..c163683b578 100644 --- a/src/main/resources/l10n/JabRef_fr.properties +++ b/src/main/resources/l10n/JabRef_fr.properties @@ -149,6 +149,7 @@ Broken\ link=Lien invalide Browse=Explorer by=par +The\ conflicting\ fields\ of\ these\ entries\ will\ be\ merged\ into\ the\ 'Comment'\ field.=Les champs discordants de ces entrées seront fusionnés dans le champ « Comment ». Cancel=Annuler @@ -211,6 +212,7 @@ Color\ for\ marking\ incomplete\ entries=Couleur pour marquer les entrées incom Column\ width=Largeur de colonne Command\ line\ id=Identifiant de la ligne de commande +Comments=Commentaires Contained\ in=Contenu dans @@ -560,6 +562,7 @@ Get\ fulltext=Obtenir le document Gray\ out\ non-hits=Griser les entrées non correspondantes Groups=Groupes +has/have\ both\ a\ 'Comment'\ and\ a\ 'Review'\ field.=a/ont tous les deux un champ « Comment » et un champ « Review ». Have\ you\ chosen\ the\ correct\ package\ path?=Avez-vous choisi le bon chemin pour le paquetage ? @@ -1009,6 +1012,7 @@ Resolve\ strings\ for\ standard\ BibTeX\ fields\ only=Traiter les chaînes pour resolved=résolu Review=Remarques Review\ changes=Revoir les changements +Review\ Field\ Migration=Migration des champs « Review » Right=Droite @@ -1101,6 +1105,7 @@ Show\ URL/DOI\ column=Afficher la colonne URL/DOI Show\ validation\ messages=Afficher les messages de validation Simple\ HTML=HTML (simple) +Since\ the\ 'Review'\ field\ was\ deprecated\ in\ JabRef\ 4.2,\ these\ two\ fields\ are\ about\ to\ be\ merged\ into\ the\ 'Comment'\ field.=Étant donné que le champ « Review » est obsolète dans JabRef 4.2, ces deux champs sont sur le point d’être fusionné dans le champ « Comment ». Size=Taille From 8c589a250926360ddd62b8d9b3eaccc58662e29a Mon Sep 17 00:00:00 2001 From: Stefan Kolb Date: Mon, 19 Feb 2018 10:36:36 +0100 Subject: [PATCH 71/94] Inline loc.org xsds --- src/main/resources/xjc/mods/mods-3-6.xsd | 348 +++++++++++------------ src/main/resources/xjc/mods/xlink.xsd | 75 +++++ src/main/resources/xjc/mods/xml.xsd | 146 ++++++++++ 3 files changed, 395 insertions(+), 174 deletions(-) create mode 100644 src/main/resources/xjc/mods/xlink.xsd create mode 100644 src/main/resources/xjc/mods/xml.xsd diff --git a/src/main/resources/xjc/mods/mods-3-6.xsd b/src/main/resources/xjc/mods/mods-3-6.xsd index 5c536f87d2b..f7cbb773536 100644 --- a/src/main/resources/xjc/mods/mods-3-6.xsd +++ b/src/main/resources/xjc/mods/mods-3-6.xsd @@ -3,17 +3,17 @@ - - - - - - @@ -305,7 +305,7 @@ End list of "top level" MODS elements - @@ -321,7 +321,7 @@ End list of "top level" MODS elements **************************************************** * Top Level Element * -***************************************************** +***************************************************** --> @@ -339,10 +339,10 @@ End list of "top level" MODS elements - @@ -357,8 +357,8 @@ End list of "top level" MODS elements - @@ -368,7 +368,7 @@ End list of "top level" MODS elements @@ -391,7 +391,7 @@ End list of "top level" MODS elements - @@ -409,7 +409,7 @@ End list of "top level" MODS elements @@ -423,8 +423,8 @@ End list of "top level" MODS elements - @@ -444,7 +444,7 @@ End list of "top level" MODS elements @@ -476,17 +476,17 @@ End list of "top level" MODS elements - - - - + - - @@ -554,7 +554,7 @@ Choice two. With . @@ -582,7 +582,7 @@ Choice two. With . - @@ -592,8 +592,8 @@ Choice two. With . - @@ -604,15 +604,15 @@ Choice two. With . - - @@ -628,11 +628,11 @@ Choice two. With . - @@ -658,9 +658,9 @@ Choice two. With . - @@ -671,7 +671,7 @@ Choice two. With . - @@ -694,12 +694,12 @@ Choice two. With . - - @@ -745,7 +745,7 @@ Choice two. With . @@ -755,11 +755,11 @@ Choice two. With . - @@ -774,14 +774,14 @@ Choice two. With . - @@ -801,10 +801,10 @@ Choice two. With . - @@ -820,8 +820,8 @@ Choice two. With . - @@ -838,11 +838,11 @@ Choice two. With . @@ -859,7 +859,7 @@ Choice two. With . **************************************************** * Top Level Element * -***************************************************** +***************************************************** --> @@ -879,10 +879,10 @@ Choice two. With . - @@ -893,12 +893,12 @@ Choice two. With . - @@ -910,7 +910,7 @@ Choice two. With . @@ -923,7 +923,7 @@ Choice two. With . @@ -939,9 +939,9 @@ Choice two. With . @@ -954,10 +954,10 @@ Choice two. With . - - + @@ -965,16 +965,16 @@ Choice two. With . - @@ -989,13 +989,13 @@ Choice two. With . - @@ -1018,25 +1018,25 @@ Choice two. With . - + --> - + - + - @@ -1064,12 +1064,12 @@ Choice two. With . - @@ -1081,7 +1081,7 @@ Choice two. With . - @@ -1108,7 +1108,7 @@ Choice two. With . - @@ -1139,7 +1139,7 @@ Choice two. With . @@ -1160,8 +1160,8 @@ Choice two. With . - @@ -1185,22 +1185,22 @@ Choice two. With . - - + @@ -1211,7 +1211,7 @@ Choice two. With . - @@ -1225,7 +1225,7 @@ Choice two. With . - + @@ -1235,7 +1235,7 @@ Choice two. With . - + @@ -1245,7 +1245,7 @@ Choice two. With . - @@ -1256,27 +1256,27 @@ Choice two. With . - - - + - - + - + @@ -1285,14 +1285,14 @@ Choice two. With . - @@ -1308,11 +1308,11 @@ Choice two. With . - @@ -1363,13 +1363,13 @@ Choice two. With . - @@ -1380,11 +1380,11 @@ Choice two. With . - + @@ -1401,10 +1401,10 @@ Choice two. With . - @@ -1422,7 +1422,7 @@ Choice two. With . - @@ -1444,7 +1444,7 @@ String Definitions @@ -1453,8 +1453,8 @@ String Definitions - @@ -1463,13 +1463,13 @@ String Definitions - - @@ -1477,8 +1477,8 @@ String Definitions - @@ -1486,19 +1486,19 @@ String Definitions - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/xjc/mods/xml.xsd b/src/main/resources/xjc/mods/xml.xsd new file mode 100644 index 00000000000..bb367ccf5dc --- /dev/null +++ b/src/main/resources/xjc/mods/xml.xsd @@ -0,0 +1,146 @@ + + + + + + See http://www.w3.org/XML/1998/namespace.html and + http://www.w3.org/TR/REC-xml for information about this namespace. + + This schema document describes the XML namespace, in a form + suitable for import by other schema documents. + + Note that local names in this namespace are intended to be defined + only by the World Wide Web Consortium or its subgroups. The + following names are currently defined in this namespace and should + not be used with conflicting semantics by any Working Group, + specification, or document instance: + + base (as an attribute name): denotes an attribute whose value + provides a URI to be used as the base for interpreting any + relative URIs in the scope of the element on which it + appears; its value is inherited. This name is reserved + by virtue of its definition in the XML Base specification. + + id (as an attribute name): denotes an attribute whose value + should be interpreted as if declared to be of type ID. + The xml:id specification is not yet a W3C Recommendation, + but this attribute is included here to facilitate experimentation + with the mechanisms it proposes. Note that it is _not_ included + in the specialAttrs attribute group. + + lang (as an attribute name): denotes an attribute whose value + is a language code for the natural language of the content of + any element; its value is inherited. This name is reserved + by virtue of its definition in the XML specification. + + space (as an attribute name): denotes an attribute whose + value is a keyword indicating what whitespace processing + discipline is intended for the content of the element; its + value is inherited. This name is reserved by virtue of its + definition in the XML specification. + + Father (in any context at all): denotes Jon Bosak, the chair of + the original XML Working Group. This name is reserved by + the following decision of the W3C XML Plenary and + XML Coordination groups: + + In appreciation for his vision, leadership and dedication + the W3C XML Plenary on this 10th day of February, 2000 + reserves for Jon Bosak in perpetuity the XML name + xml:Father + + + + + This schema defines attributes and an attribute group + suitable for use by + schemas wishing to allow xml:base, xml:lang, xml:space or xml:id + attributes on elements they define. + + To enable this, such a schema must import this schema + for the XML namespace, e.g. as follows: + <schema . . .> + . . . + <import namespace="http://www.w3.org/XML/1998/namespace" + schemaLocation="http://www.w3.org/2001/xml.xsd"/> + + Subsequently, qualified reference to any of the attributes + or the group defined below will have the desired effect, e.g. + + <type . . .> + . . . + <attributeGroup ref="xml:specialAttrs"/> + + will define a type which will schema-validate an instance + element with any of those attributes + + + + In keeping with the XML Schema WG's standard versioning + policy, this schema document will persist at + http://www.w3.org/2005/08/xml.xsd. + At the date of issue it can also be found at + http://www.w3.org/2001/xml.xsd. + The schema document at that URI may however change in the future, + in order to remain compatible with the latest version of XML Schema + itself, or with the XML namespace itself. In other words, if the XML + Schema or XML namespaces change, the version of this document at + http://www.w3.org/2001/xml.xsd will change + accordingly; the version at + http://www.w3.org/2005/08/xml.xsd will not change. + + + + + + Attempting to install the relevant ISO 2- and 3-letter + codes as the enumerated possible values is probably never + going to be a realistic possibility. See + RFC 3066 at http://www.ietf.org/rfc/rfc3066.txt and the IANA registry + at http://www.iana.org/assignments/lang-tag-apps.htm for + further information. + + The union allows for the 'un-declaration' of xml:lang with + the empty string. + + + + + + + + + + + + + + + + + + + + + + + + See http://www.w3.org/TR/xmlbase/ for + information about this attribute. + + + + + + See http://www.w3.org/TR/xml-id/ for + information about this attribute. + + + + + + + + + + \ No newline at end of file From 25c97db6a0cddacbd8d29d9b0cad3782b9eaed0d Mon Sep 17 00:00:00 2001 From: Linus Dietz Date: Mon, 19 Feb 2018 11:05:23 +0100 Subject: [PATCH 72/94] Update MODS from 3.7 -> 3.7 (#3741) --- .../xjc/mods/{mods-3-6.xsd => mods-3-7.xsd} | 473 +++++++++--------- src/main/resources/xjc/mods/mods-binding.xjb | 62 +-- xjc.gradle | 2 +- 3 files changed, 255 insertions(+), 282 deletions(-) rename src/main/resources/xjc/mods/{mods-3-6.xsd => mods-3-7.xsd} (85%) diff --git a/src/main/resources/xjc/mods/mods-3-6.xsd b/src/main/resources/xjc/mods/mods-3-7.xsd similarity index 85% rename from src/main/resources/xjc/mods/mods-3-6.xsd rename to src/main/resources/xjc/mods/mods-3-7.xsd index f7cbb773536..5672509aa9a 100644 --- a/src/main/resources/xjc/mods/mods-3-6.xsd +++ b/src/main/resources/xjc/mods/mods-3-7.xsd @@ -1,72 +1,50 @@ - + - - - - - - @@ -305,7 +284,7 @@ End list of "top level" MODS elements - @@ -321,7 +300,7 @@ End list of "top level" MODS elements **************************************************** * Top Level Element * -***************************************************** +***************************************************** --> @@ -339,10 +318,10 @@ End list of "top level" MODS elements - @@ -357,8 +336,8 @@ End list of "top level" MODS elements - @@ -368,7 +347,7 @@ End list of "top level" MODS elements @@ -391,15 +370,13 @@ End list of "top level" MODS elements - - - - + @@ -409,7 +386,7 @@ End list of "top level" MODS elements @@ -423,8 +400,8 @@ End list of "top level" MODS elements - @@ -444,7 +421,7 @@ End list of "top level" MODS elements @@ -476,17 +453,17 @@ End list of "top level" MODS elements - - - - + + + - - @@ -554,7 +528,7 @@ Choice two. With . @@ -575,14 +549,15 @@ Choice two. With . - + - - - + + + @@ -592,8 +567,8 @@ Choice two. With . - @@ -604,15 +579,36 @@ Choice two. With . - + + + + + + + + + + + + + + + + + + @@ -628,11 +624,11 @@ Choice two. With . - @@ -658,9 +654,9 @@ Choice two. With . - @@ -671,7 +667,7 @@ Choice two. With . - @@ -694,12 +690,28 @@ Choice two. With . - - - + + + + + + + + + + + + + @@ -741,11 +753,16 @@ Choice two. With . + + + @@ -755,11 +772,11 @@ Choice two. With . - @@ -774,14 +791,14 @@ Choice two. With . - @@ -801,10 +818,10 @@ Choice two. With . - @@ -820,8 +837,8 @@ Choice two. With . - @@ -838,11 +855,11 @@ Choice two. With . @@ -859,7 +876,7 @@ Choice two. With . **************************************************** * Top Level Element * -***************************************************** +***************************************************** --> @@ -879,10 +896,10 @@ Choice two. With . - @@ -893,12 +910,12 @@ Choice two. With . - @@ -910,7 +927,7 @@ Choice two. With . @@ -923,7 +940,7 @@ Choice two. With . @@ -939,9 +956,9 @@ Choice two. With . @@ -954,10 +971,8 @@ Choice two. With . - - + @@ -965,16 +980,14 @@ Choice two. With . - @@ -989,13 +1002,13 @@ Choice two. With . - @@ -1018,25 +1031,21 @@ Choice two. With . - + - - - + - @@ -1064,12 +1073,12 @@ Choice two. With . - @@ -1081,7 +1090,7 @@ Choice two. With . - @@ -1108,7 +1117,7 @@ Choice two. With . - @@ -1118,7 +1127,6 @@ Choice two. With . - @@ -1139,7 +1147,7 @@ Choice two. With . @@ -1160,8 +1168,8 @@ Choice two. With . - @@ -1171,10 +1179,9 @@ Choice two. With . - + - @@ -1185,23 +1192,7 @@ Choice two. With . - - - + @@ -1211,7 +1202,7 @@ Choice two. With . - @@ -1225,7 +1216,7 @@ Choice two. With . - + @@ -1235,7 +1226,7 @@ Choice two. With . - + @@ -1245,8 +1236,8 @@ Choice two. With . - @@ -1256,43 +1247,40 @@ Choice two. With . - - - + - - + - + - - @@ -1308,11 +1296,11 @@ Choice two. With . - @@ -1363,14 +1351,14 @@ Choice two. With . - @@ -1380,17 +1368,24 @@ Choice two. With . - + - + + @@ -1399,30 +1394,8 @@ Choice two. With . - - - - - - - - - - - - - - - - - - - @@ -1444,7 +1417,7 @@ String Definitions @@ -1453,8 +1426,8 @@ String Definitions - @@ -1463,13 +1436,13 @@ String Definitions - - @@ -1477,8 +1450,8 @@ String Definitions - @@ -1486,19 +1459,19 @@ String Definitions - - - + ---- From e97aaf8da23d5c41b213c0de20c0c902d71e873c Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Tue, 20 Feb 2018 10:26:19 +0100 Subject: [PATCH 75/94] Add link to contribute.jabref.org (#3748) * Add link to contribute.jabref.org * Changed link text * Rewrote sentence --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 4fb2b7e5a2e..5cd2607dbc4 100644 --- a/README.md +++ b/README.md @@ -80,6 +80,8 @@ An explanation of donation possibilities and usage of donations is available at [![Join the chat at https://gitter.im/JabRef/jabref](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/JabRef/jabref?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![OpenHub](https://www.openhub.net/p/jabref/widgets/project_thin_badge.gif)](https://www.openhub.net/p/jabref) +> Not a programmer? [Learn how to help.](http://contribute.jabref.org) + Want to be part of a free and open-source project that tens of thousands scientist use every day? Check out our [issue tracker](https://github.com/JabRef/jabref/issues) to find something to work on. You are also welcome to contribute new features. From 7d21f575814199c13581798094c3b2d40f153093 Mon Sep 17 00:00:00 2001 From: Linus Dietz Date: Tue, 20 Feb 2018 10:36:21 +0100 Subject: [PATCH 76/94] update gradle --- gradle/wrapper/gradle-wrapper.jar | Bin 54333 -> 54727 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 99340b4ad18d3c7e764794d300ffd35017036793..27768f1bbac3ce2d055b20d521f12da78d331e8e 100644 GIT binary patch delta 16621 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 LgBlz7PwoE)% Date: Tue, 20 Feb 2018 10:42:10 +0100 Subject: [PATCH 77/94] Fix exceptions for jacoco --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 05c333f494f..526dd779295 100644 --- a/build.gradle +++ b/build.gradle @@ -231,12 +231,12 @@ dependencyUpdates.resolutionStrategy = { selection.reject("http://dev.mysql.com/downloads/connector/j/ lists the version 5.* as last stable version.") } } - withModule("org.jacoco.agent") { ComponentSelection selection -> + withModule("org.jacoco:org.jacoco.agent") { ComponentSelection selection -> if (selection.candidate.version.equals("0.8.0")) { selection.reject("As a native plugin we cannot control the actual version of jacoco. This dependency should be hidden.") } } - withModule("org.jacoco.ant") { ComponentSelection selection -> + withModule("org.jacoco:org.jacoco.ant") { ComponentSelection selection -> if (selection.candidate.version.equals("0.8.0")) { selection.reject("As a native plugin we cannot control the actual version of jacoco. This dependency should be hidden.") } From 1e4c2d8f842b719a6295dab8f2becb8b44deab95 Mon Sep 17 00:00:00 2001 From: Linus Dietz Date: Tue, 20 Feb 2018 10:42:59 +0100 Subject: [PATCH 78/94] Update wiremock from 2.14.0 -> 2.15.0 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 526dd779295..9dd21067ae5 100644 --- a/build.gradle +++ b/build.gradle @@ -163,7 +163,7 @@ dependencies { testRuntime 'org.apache.logging.log4j:log4j-core:2.10.0' testRuntime 'org.apache.logging.log4j:log4j-jul:2.10.0' testCompile 'org.mockito:mockito-core:2.13.0' - testCompile 'com.github.tomakehurst:wiremock:2.14.0' + testCompile 'com.github.tomakehurst:wiremock:2.15.0' testCompile 'org.assertj:assertj-swing-junit:3.8.0' testCompile 'org.reflections:reflections:0.9.11' testCompile 'org.xmlunit:xmlunit-core:2.5.1' From 0dddf39daf2afbe154035c1cb78252a957a08a39 Mon Sep 17 00:00:00 2001 From: Linus Dietz Date: Tue, 20 Feb 2018 10:43:49 +0100 Subject: [PATCH 79/94] Update Mockito from 2.13.0 -> 2.15.0 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 9dd21067ae5..ccab485504e 100644 --- a/build.gradle +++ b/build.gradle @@ -162,7 +162,7 @@ dependencies { testCompile 'org.junit.platform:junit-platform-launcher:1.1.0-M2' testRuntime 'org.apache.logging.log4j:log4j-core:2.10.0' testRuntime 'org.apache.logging.log4j:log4j-jul:2.10.0' - testCompile 'org.mockito:mockito-core:2.13.0' + testCompile 'org.mockito:mockito-core:2.15.0' testCompile 'com.github.tomakehurst:wiremock:2.15.0' testCompile 'org.assertj:assertj-swing-junit:3.8.0' testCompile 'org.reflections:reflections:0.9.11' From d563a60f3dd6df5c60470f20066325190a678103 Mon Sep 17 00:00:00 2001 From: Linus Dietz Date: Tue, 20 Feb 2018 10:45:54 +0100 Subject: [PATCH 80/94] Update JUnit from 5.1.0-M2 -> 5.1.0 --- build.gradle | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/build.gradle b/build.gradle index ccab485504e..f48e06edc96 100644 --- a/build.gradle +++ b/build.gradle @@ -13,7 +13,7 @@ buildscript { } } dependencies { - classpath 'org.junit.platform:junit-platform-gradle-plugin:1.1.0-M1' + classpath 'org.junit.platform:junit-platform-gradle-plugin:1.1.0' } } @@ -155,11 +155,11 @@ dependencies { compile group: 'com.microsoft.azure', name: 'applicationinsights-core', version: '1.0.9' compile group: 'com.microsoft.azure', name: 'applicationinsights-logging-log4j2', version: '1.0.9' - testCompile 'org.junit.jupiter:junit-jupiter-api:5.1.0-M2' - testCompile 'org.junit.jupiter:junit-jupiter-params:5.1.0-M2' - testRuntime 'org.junit.jupiter:junit-jupiter-engine:5.1.0-M2' - testRuntime 'org.junit.vintage:junit-vintage-engine:5.1.0-M2' - testCompile 'org.junit.platform:junit-platform-launcher:1.1.0-M2' + testCompile 'org.junit.jupiter:junit-jupiter-api:5.1.0' + testCompile 'org.junit.jupiter:junit-jupiter-params:5.1.0' + testRuntime 'org.junit.jupiter:junit-jupiter-engine:5.1.0' + testRuntime 'org.junit.vintage:junit-vintage-engine:5.1.0' + testCompile 'org.junit.platform:junit-platform-launcher:1.1.0' testRuntime 'org.apache.logging.log4j:log4j-core:2.10.0' testRuntime 'org.apache.logging.log4j:log4j-jul:2.10.0' testCompile 'org.mockito:mockito-core:2.15.0' From ce034cbd8fa20299568c2c5ba264f992af8b893c Mon Sep 17 00:00:00 2001 From: Linus Dietz Date: Tue, 20 Feb 2018 14:06:20 +0100 Subject: [PATCH 81/94] Incorporate suggestions by @Siedlerchr --- ...IntoComment.java => MergeReviewIntoCommentAction.java} | 8 ++++++-- ...java => MergeReviewIntoCommentConfirmationDialog.java} | 4 ++-- .../jabref/gui/importer/actions/OpenDatabaseAction.java | 2 +- ...ava => MergeReviewIntoCommentActionMigrationTest.java} | 2 +- 4 files changed, 10 insertions(+), 6 deletions(-) rename src/main/java/org/jabref/gui/importer/actions/{MergeReviewIntoComment.java => MergeReviewIntoCommentAction.java} (66%) rename src/main/java/org/jabref/gui/importer/actions/{MergeReviewIntoCommentConfirmation.java => MergeReviewIntoCommentConfirmationDialog.java} (91%) rename src/test/java/org/jabref/logic/importer/migrations/{MergeReviewIntoCommentMigrationTest.java => MergeReviewIntoCommentActionMigrationTest.java} (98%) diff --git a/src/main/java/org/jabref/gui/importer/actions/MergeReviewIntoComment.java b/src/main/java/org/jabref/gui/importer/actions/MergeReviewIntoCommentAction.java similarity index 66% rename from src/main/java/org/jabref/gui/importer/actions/MergeReviewIntoComment.java rename to src/main/java/org/jabref/gui/importer/actions/MergeReviewIntoCommentAction.java index 61fd6fb028b..71b52e42eaf 100644 --- a/src/main/java/org/jabref/gui/importer/actions/MergeReviewIntoComment.java +++ b/src/main/java/org/jabref/gui/importer/actions/MergeReviewIntoCommentAction.java @@ -1,10 +1,13 @@ package org.jabref.gui.importer.actions; +import java.util.List; + import org.jabref.gui.BasePanel; import org.jabref.logic.importer.ParserResult; import org.jabref.logic.migrations.MergeReviewIntoCommentMigration; +import org.jabref.model.entry.BibEntry; -public class MergeReviewIntoComment implements GUIPostOpenAction { +public class MergeReviewIntoCommentAction implements GUIPostOpenAction { @Override public boolean isActionNecessary(ParserResult parserResult) { @@ -16,7 +19,8 @@ public void performAction(BasePanel basePanel, ParserResult parserResult) { MergeReviewIntoCommentMigration migration = new MergeReviewIntoCommentMigration(); migration.performMigration(parserResult); - if (new MergeReviewIntoCommentConfirmation(basePanel).askUserForMerge(MergeReviewIntoCommentMigration.collectConflicts(parserResult))) { + List conflicts = MergeReviewIntoCommentMigration.collectConflicts(parserResult); + if (new MergeReviewIntoCommentConfirmationDialog(basePanel).askUserForMerge(conflicts)) { migration.performConflictingMigration(parserResult); } } diff --git a/src/main/java/org/jabref/gui/importer/actions/MergeReviewIntoCommentConfirmation.java b/src/main/java/org/jabref/gui/importer/actions/MergeReviewIntoCommentConfirmationDialog.java similarity index 91% rename from src/main/java/org/jabref/gui/importer/actions/MergeReviewIntoCommentConfirmation.java rename to src/main/java/org/jabref/gui/importer/actions/MergeReviewIntoCommentConfirmationDialog.java index f4746fbe94b..4a7eaedd8f0 100644 --- a/src/main/java/org/jabref/gui/importer/actions/MergeReviewIntoCommentConfirmation.java +++ b/src/main/java/org/jabref/gui/importer/actions/MergeReviewIntoCommentConfirmationDialog.java @@ -10,11 +10,11 @@ import org.jabref.logic.l10n.Localization; import org.jabref.model.entry.BibEntry; -public class MergeReviewIntoCommentConfirmation { +public class MergeReviewIntoCommentConfirmationDialog { private final BasePanel panel; - public MergeReviewIntoCommentConfirmation(BasePanel panel) { + public MergeReviewIntoCommentConfirmationDialog(BasePanel panel) { this.panel = panel; } diff --git a/src/main/java/org/jabref/gui/importer/actions/OpenDatabaseAction.java b/src/main/java/org/jabref/gui/importer/actions/OpenDatabaseAction.java index d0395b7d626..c4fc191e10f 100644 --- a/src/main/java/org/jabref/gui/importer/actions/OpenDatabaseAction.java +++ b/src/main/java/org/jabref/gui/importer/actions/OpenDatabaseAction.java @@ -59,7 +59,7 @@ public class OpenDatabaseAction extends MnemonicAwareAction { private static final List POST_OPEN_ACTIONS = Arrays.asList( // Migrations: // Warning for migrating the Review into the Comment field - new MergeReviewIntoComment(), + new MergeReviewIntoCommentAction(), // External file handling system in version 2.3: new FileLinksUpgradeWarning(), diff --git a/src/test/java/org/jabref/logic/importer/migrations/MergeReviewIntoCommentMigrationTest.java b/src/test/java/org/jabref/logic/importer/migrations/MergeReviewIntoCommentActionMigrationTest.java similarity index 98% rename from src/test/java/org/jabref/logic/importer/migrations/MergeReviewIntoCommentMigrationTest.java rename to src/test/java/org/jabref/logic/importer/migrations/MergeReviewIntoCommentActionMigrationTest.java index 8cc331f44ea..2e9f09c2350 100644 --- a/src/test/java/org/jabref/logic/importer/migrations/MergeReviewIntoCommentMigrationTest.java +++ b/src/test/java/org/jabref/logic/importer/migrations/MergeReviewIntoCommentActionMigrationTest.java @@ -14,7 +14,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; -class MergeReviewIntoCommentMigrationTest { +class MergeReviewIntoCommentActionMigrationTest { private MergeReviewIntoCommentMigration action; @BeforeEach From ea8ccb39c73d4f977592eadc5bd3a64c0fafdcab Mon Sep 17 00:00:00 2001 From: Johannes Manner Date: Tue, 20 Feb 2018 14:59:12 +0100 Subject: [PATCH 82/94] Improve Dublin Core (#3710) This fixes #938 - Reading and writing multiple dublinCore entries works: XMPUtilWriter supports mutliple metadata entries in dublinCore and a single entry in the PDDocumentInformation. If you want to test the reading of multiple entries, the PDF file JabRef_multipleMetaEntries.pdf contains three metadata entries in DublinCore for testing locally. - Removed to much code when refactoring the XMPUtil. Non XMP metadata are also relevent, when retrieving org.apache.pdfbox.pdmodel.PDDocumentInformation - Update pdfbox and fontbox from 1.8.13 to 2.0.8 and migritate from jempbox to xmpbox. See pull https://github.com/JabRef/jabref/pull/1096. - Refactor extraction from DublinCoreSchema - The tests cover the most important use cases, which include reading and writing metadata from pdf files. Both formats, DublinCore and PDMetadata (which are no XMP metadata) are tested. - Separated XMPUtils in a reader and a writer utitlity class. - add meaningful names in DublinCoreExtractor and use StringUtils.isNullOrEmpty - Log exception in XMPUtilShared --- build.gradle | 17 +- src/main/java/org/jabref/cli/XMPUtilMain.java | 85 +- .../PdfDocumentPageViewModel.java | 11 +- .../documentviewer/PdfDocumentViewModel.java | 11 +- .../gui/externalfiles/DroppedFileHandler.java | 4 +- .../gui/externalfiles/WriteXMPAction.java | 4 +- .../gui/fieldeditors/LinkedFileViewModel.java | 4 +- .../gui/importer/EntryFromPDFCreator.java | 69 - .../logic/importer/ImportFormatReader.java | 4 +- .../fileformat/PdfContentImporter.java | 8 +- .../importer/fileformat/PdfXmpImporter.java | 13 +- .../logic/pdf/PdfAnnotationImporter.java | 15 +- .../org/jabref/logic/pdf/TextExtractor.java | 2 +- .../xmp/DocumentInformationExtractor.java | 99 ++ .../jabref/logic/xmp/DublinCoreExtractor.java | 388 +++++ .../org/jabref/logic/xmp/XMPSchemaBibtex.java | 324 ---- .../java/org/jabref/logic/xmp/XMPUtil.java | 1063 ------------- ...MPPreferences.java => XmpPreferences.java} | 4 +- .../org/jabref/logic/xmp/XmpUtilReader.java | 155 ++ .../org/jabref/logic/xmp/XmpUtilShared.java | 60 + .../org/jabref/logic/xmp/XmpUtilWriter.java | 281 ++++ .../org/jabref/model/pdf/FileAnnotation.java | 4 +- .../org/jabref/pdfimport/ImportDialog.java | 4 +- .../org/jabref/pdfimport/PdfImporter.java | 37 +- .../jabref/preferences/JabRefPreferences.java | 6 +- .../ImportFormatReaderIntegrationTest.java | 4 +- .../ImportFormatReaderTestParameterless.java | 4 +- .../jabref/logic/importer/ImporterTest.java | 4 +- .../fileformat/PdfXmpImporterTest.java | 4 +- .../jabref/logic/xmp/XMPSchemaBibtexTest.java | 285 ---- .../org/jabref/logic/xmp/XMPUtilTest.java | 1397 ----------------- .../jabref/logic/xmp/XmpUtilReaderTest.java | 111 ++ .../jabref/logic/xmp/XmpUtilWriterTest.java | 147 ++ .../logic/xmp/JabRef_multipleMetaEntries.pdf | Bin 0 -> 5197 bytes .../org/jabref/logic/xmp/PD_metadata.bib | 6 + .../org/jabref/logic/xmp/PD_metadata.pdf | Bin 0 -> 8952 bytes .../jabref/logic/xmp/article_dublinCore.bib | 23 + .../jabref/logic/xmp/article_dublinCore.pdf | Bin 0 -> 311223 bytes .../org/jabref/logic/xmp/empty_metadata.pdf | Bin 0 -> 292231 bytes 39 files changed, 1389 insertions(+), 3268 deletions(-) create mode 100644 src/main/java/org/jabref/logic/xmp/DocumentInformationExtractor.java create mode 100644 src/main/java/org/jabref/logic/xmp/DublinCoreExtractor.java delete mode 100644 src/main/java/org/jabref/logic/xmp/XMPSchemaBibtex.java delete mode 100644 src/main/java/org/jabref/logic/xmp/XMPUtil.java rename src/main/java/org/jabref/logic/xmp/{XMPPreferences.java => XmpPreferences.java} (87%) create mode 100644 src/main/java/org/jabref/logic/xmp/XmpUtilReader.java create mode 100644 src/main/java/org/jabref/logic/xmp/XmpUtilShared.java create mode 100644 src/main/java/org/jabref/logic/xmp/XmpUtilWriter.java delete mode 100644 src/test/java/org/jabref/logic/xmp/XMPSchemaBibtexTest.java delete mode 100644 src/test/java/org/jabref/logic/xmp/XMPUtilTest.java create mode 100644 src/test/java/org/jabref/logic/xmp/XmpUtilReaderTest.java create mode 100644 src/test/java/org/jabref/logic/xmp/XmpUtilWriterTest.java create mode 100644 src/test/resources/org/jabref/logic/xmp/JabRef_multipleMetaEntries.pdf create mode 100644 src/test/resources/org/jabref/logic/xmp/PD_metadata.bib create mode 100644 src/test/resources/org/jabref/logic/xmp/PD_metadata.pdf create mode 100644 src/test/resources/org/jabref/logic/xmp/article_dublinCore.bib create mode 100644 src/test/resources/org/jabref/logic/xmp/article_dublinCore.pdf create mode 100644 src/test/resources/org/jabref/logic/xmp/empty_metadata.pdf diff --git a/build.gradle b/build.gradle index f48e06edc96..67c649dc039 100644 --- a/build.gradle +++ b/build.gradle @@ -90,10 +90,9 @@ dependencies { compile 'com.jgoodies:jgoodies-common:1.8.1' compile 'com.jgoodies:jgoodies-forms:1.9.0' - // update to 2.0.x is not possible - see https://github.com/JabRef/jabref/pull/1096#issuecomment-208857517 - compile 'org.apache.pdfbox:pdfbox:1.8.13' - compile 'org.apache.pdfbox:fontbox:1.8.13' - compile 'org.apache.pdfbox:jempbox:1.8.13' + compile 'org.apache.pdfbox:pdfbox:2.0.8' + compile 'org.apache.pdfbox:fontbox:2.0.8' + compile 'org.apache.pdfbox:xmpbox:2.0.8' // required for reading write-protected PDFs - see https://github.com/JabRef/jabref/pull/942#issuecomment-209252635 compile 'org.bouncycastle:bcprov-jdk15on:1.59' @@ -216,16 +215,6 @@ dependencyUpdates.resolutionStrategy = { selection.reject("Cannot be upgraded to version 2") } } - withModule("org.apache.pdfbox:fontbox") { ComponentSelection selection -> - if (selection.candidate.version ==~ /2.*/) { - selection.reject("update to 2.0.x is not possible - see https://github.com/JabRef/jabref/pull/1096#issuecomment-208857517") - } - } - withModule("org.apache.pdfbox:pdfbox") { ComponentSelection selection -> - if (selection.candidate.version ==~ /2.*/) { - selection.reject("update to 2.0.x is not possible - see https://github.com/JabRef/jabref/pull/1096#issuecomment-208857517") - } - } withModule("mysql:mysql-connector-java") { ComponentSelection selection -> if (selection.candidate.version ==~ /[6-9].*/) { selection.reject("http://dev.mysql.com/downloads/connector/j/ lists the version 5.* as last stable version.") diff --git a/src/main/java/org/jabref/cli/XMPUtilMain.java b/src/main/java/org/jabref/cli/XMPUtilMain.java index 517f572017c..430c49541bd 100644 --- a/src/main/java/org/jabref/cli/XMPUtilMain.java +++ b/src/main/java/org/jabref/cli/XMPUtilMain.java @@ -1,10 +1,9 @@ package org.jabref.cli; -import java.io.File; import java.io.FileReader; import java.io.IOException; import java.io.StringWriter; -import java.nio.charset.StandardCharsets; +import java.nio.file.Paths; import java.util.Collection; import java.util.List; import java.util.Optional; @@ -17,14 +16,15 @@ import org.jabref.logic.importer.ImportFormatPreferences; import org.jabref.logic.importer.ParserResult; import org.jabref.logic.importer.fileformat.BibtexParser; -import org.jabref.logic.xmp.XMPPreferences; -import org.jabref.logic.xmp.XMPUtil; +import org.jabref.logic.xmp.XmpPreferences; +import org.jabref.logic.xmp.XmpUtilReader; +import org.jabref.logic.xmp.XmpUtilWriter; import org.jabref.model.database.BibDatabaseMode; import org.jabref.model.entry.BibEntry; import org.jabref.preferences.JabRefPreferences; -import org.apache.jempbox.impl.XMLUtil; -import org.apache.jempbox.xmp.XMPMetadata; +import org.apache.xmpbox.XMPMetadata; +import org.apache.xmpbox.xml.XmpSerializer; public class XMPUtilMain { @@ -62,18 +62,16 @@ public static void main(String[] args) throws IOException, TransformerException Globals.prefs = JabRefPreferences.getInstance(); } - XMPPreferences xmpPreferences = Globals.prefs.getXMPPreferences(); + XmpPreferences xmpPreferences = Globals.prefs.getXMPPreferences(); ImportFormatPreferences importFormatPreferences = Globals.prefs.getImportFormatPreferences(); - switch (args.length) { - case 0: + int argsLength = args.length; + if (argsLength == 0) { usage(); - break; - case 1: - + } else if (argsLength == 1) { if (args[0].endsWith(".pdf")) { // Read from pdf and write as BibTex - List l = XMPUtil.readXMP(new File(args[0]), xmpPreferences); + List l = XmpUtilReader.readXmp(args[0], xmpPreferences); BibEntryWriter bibtexEntryWriter = new BibEntryWriter( new LatexFieldFormatter(Globals.prefs.getLatexFieldFormatterPreferences()), false); @@ -92,63 +90,62 @@ public static void main(String[] args) throws IOException, TransformerException if (entries.isEmpty()) { System.err.println("Could not find BibEntry in " + args[0]); - } else { - System.out.println(XMPUtil.toXMP(entries, result.getDatabase(), xmpPreferences)); } } } else { usage(); } - break; - case 2: + } else if (argsLength == 2) { if ("-x".equals(args[0]) && args[1].endsWith(".pdf")) { // Read from pdf and write as BibTex - Optional meta = XMPUtil.readRawXMP(new File(args[1])); + List meta = XmpUtilReader.readRawXmp(Paths.get(args[1])); - if (meta.isPresent()) { - XMLUtil.save(meta.get().getXMPDocument(), System.out, StandardCharsets.UTF_8.name()); + if (!meta.isEmpty()) { + XmpSerializer serializer = new XmpSerializer(); + serializer.serialize(meta.get(0), System.out, true); } else { System.err.println("The given pdf does not contain any XMP-metadata."); } - break; + return; } if (args[0].endsWith(".bib") && args[1].endsWith(".pdf")) { - ParserResult result = new BibtexParser(importFormatPreferences, Globals.getFileUpdateMonitor()).parse(new FileReader(args[0])); + try (FileReader reader = new FileReader(args[0])) { + ParserResult result = new BibtexParser(importFormatPreferences, Globals.getFileUpdateMonitor()).parse(reader); - Collection entries = result.getDatabase().getEntries(); + List entries = result.getDatabase().getEntries(); - if (entries.isEmpty()) { - System.err.println("Could not find BibEntry in " + args[0]); - } else { - XMPUtil.writeXMP(new File(args[1]), entries, result.getDatabase(), false, xmpPreferences); - System.out.println("XMP written."); + if (entries.isEmpty()) { + System.err.println("Could not find BibEntry in " + args[0]); + } else { + XmpUtilWriter.writeXmp(Paths.get(args[1]), entries, result.getDatabase(), xmpPreferences); + System.out.println("XMP written."); + } } - break; + return; } usage(); - break; - case 3: + } else if (argsLength == 3) { if (!args[1].endsWith(".bib") && !args[2].endsWith(".pdf")) { usage(); - break; + return; } - ParserResult result = new BibtexParser(importFormatPreferences, Globals.getFileUpdateMonitor()).parse(new FileReader(args[1])); + try (FileReader reader = new FileReader(args[1])) { + ParserResult result = new BibtexParser(importFormatPreferences, Globals.getFileUpdateMonitor()).parse(reader); - Optional bibEntry = result.getDatabase().getEntryByKey(args[0]); + Optional bibEntry = result.getDatabase().getEntryByKey(args[0]); - if (bibEntry.isPresent()) { - XMPUtil.writeXMP(new File(args[2]), bibEntry.get(), result.getDatabase(), xmpPreferences); + if (bibEntry.isPresent()) { + XmpUtilWriter.writeXmp(Paths.get(args[2]), bibEntry.get(), result.getDatabase(), xmpPreferences); - System.out.println("XMP written."); - } else { - System.err.println("Could not find BibEntry " + args[0] + " in " + args[0]); + System.out.println("XMP written."); + } else { + System.err.println("Could not find BibEntry " + args[0] + " in " + args[0]); + } } - break; - - default: + } else { usage(); } } @@ -167,13 +164,13 @@ private static void usage() { System.out.println("Read from PDF and print raw XMP:"); System.out.println(" xmpUtil -x "); System.out - .println("Write the entry in given by to the PDF:"); + .println("Write the entry in given by to the PDF:"); System.out.println(" xmpUtil "); System.out.println("Write all entries in to the PDF:"); System.out.println(" xmpUtil "); System.out.println(""); System.out - .println("To report bugs visit https://issues.jabref.org"); + .println("To report bugs visit https://issues.jabref.org"); } } diff --git a/src/main/java/org/jabref/gui/documentviewer/PdfDocumentPageViewModel.java b/src/main/java/org/jabref/gui/documentviewer/PdfDocumentPageViewModel.java index 78a82bcd7fb..0bfb3f7775a 100644 --- a/src/main/java/org/jabref/gui/documentviewer/PdfDocumentPageViewModel.java +++ b/src/main/java/org/jabref/gui/documentviewer/PdfDocumentPageViewModel.java @@ -8,8 +8,11 @@ import javafx.embed.swing.SwingFXUtils; import javafx.scene.image.Image; +import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.common.PDRectangle; +import org.apache.pdfbox.rendering.ImageType; +import org.apache.pdfbox.rendering.PDFRenderer; /** * Represents the view model of a pdf page backed by a {@link PDPage}. @@ -18,10 +21,12 @@ public class PdfDocumentPageViewModel extends DocumentPageViewModel { private final PDPage page; private final int pageNumber; + private final PDDocument document; - public PdfDocumentPageViewModel(PDPage page, int pageNumber) { + public PdfDocumentPageViewModel(PDPage page, int pageNumber, PDDocument document) { this.page = Objects.requireNonNull(page); this.pageNumber = pageNumber; + this.document = document; } // Taken from http://stackoverflow.com/a/9417836/873661 @@ -37,10 +42,12 @@ private static BufferedImage resize(BufferedImage img, int newWidth, int newHeig } @Override + // Taken from https://stackoverflow.com/questions/23326562/apache-pdfbox-convert-pdf-to-images public Image render(int width, int height) { + PDFRenderer renderer = new PDFRenderer(document); try { int resolution = 96; - BufferedImage image = page.convertToImage(BufferedImage.TYPE_INT_RGB, 2 * resolution); + BufferedImage image = renderer.renderImageWithDPI(pageNumber, 2 * resolution, ImageType.RGB); return SwingFXUtils.toFXImage(resize(image, width, height), null); } catch (IOException e) { // TODO: LOG diff --git a/src/main/java/org/jabref/gui/documentviewer/PdfDocumentViewModel.java b/src/main/java/org/jabref/gui/documentviewer/PdfDocumentViewModel.java index e379ea4f979..9b73c87102a 100644 --- a/src/main/java/org/jabref/gui/documentviewer/PdfDocumentViewModel.java +++ b/src/main/java/org/jabref/gui/documentviewer/PdfDocumentViewModel.java @@ -8,7 +8,7 @@ import javafx.collections.ObservableList; import org.apache.pdfbox.pdmodel.PDDocument; -import org.apache.pdfbox.pdmodel.PDPage; +import org.apache.pdfbox.pdmodel.PDPageTree; public class PdfDocumentViewModel extends DocumentViewModel { @@ -21,13 +21,12 @@ public PdfDocumentViewModel(PDDocument document) { @Override public ObservableList getPages() { - @SuppressWarnings("unchecked") - List pages = document.getDocumentCatalog().getAllPages(); + PDPageTree pages = document.getDocumentCatalog().getPages(); - // There is apparently no neat way to get the page number from a PDPage...thus this old-style for loop List pdfPages = new ArrayList<>(); - for (int i = 0; i < pages.size(); i++) { - pdfPages.add(new PdfDocumentPageViewModel(pages.get(i), i + 1)); + // There is apparently no neat way to get the page number from a PDPage...thus this old-style for loop + for (int i = 0; i < pages.getCount(); i++) { + pdfPages.add(new PdfDocumentPageViewModel(pages.get(i), i + 1, document)); } return FXCollections.observableArrayList(pdfPages); } diff --git a/src/main/java/org/jabref/gui/externalfiles/DroppedFileHandler.java b/src/main/java/org/jabref/gui/externalfiles/DroppedFileHandler.java index 239c23dc36d..f8c3ce21d04 100644 --- a/src/main/java/org/jabref/gui/externalfiles/DroppedFileHandler.java +++ b/src/main/java/org/jabref/gui/externalfiles/DroppedFileHandler.java @@ -35,7 +35,7 @@ import org.jabref.gui.util.DefaultTaskExecutor; import org.jabref.logic.l10n.Localization; import org.jabref.logic.util.io.FileUtil; -import org.jabref.logic.xmp.XMPUtil; +import org.jabref.logic.xmp.XmpUtilReader; import org.jabref.model.database.BibDatabase; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.FieldName; @@ -228,7 +228,7 @@ private boolean tryXmpImport(String fileName, ExternalFileType fileType, NamedCo List xmpEntriesInFile; try { - xmpEntriesInFile = XMPUtil.readXMP(fileName, Globals.prefs.getXMPPreferences()); + xmpEntriesInFile = XmpUtilReader.readXmp(fileName, Globals.prefs.getXMPPreferences()); } catch (IOException e) { LOGGER.warn("Problem reading XMP", e); return false; diff --git a/src/main/java/org/jabref/gui/externalfiles/WriteXMPAction.java b/src/main/java/org/jabref/gui/externalfiles/WriteXMPAction.java index 9eb50acadbf..7d2f67f851b 100644 --- a/src/main/java/org/jabref/gui/externalfiles/WriteXMPAction.java +++ b/src/main/java/org/jabref/gui/externalfiles/WriteXMPAction.java @@ -31,7 +31,7 @@ import org.jabref.gui.keyboard.KeyBinding; import org.jabref.gui.worker.AbstractWorker; import org.jabref.logic.l10n.Localization; -import org.jabref.logic.xmp.XMPUtil; +import org.jabref.logic.xmp.XmpUtilWriter; import org.jabref.model.database.BibDatabase; import org.jabref.model.entry.BibEntry; @@ -133,7 +133,7 @@ public void run() { for (Path file : files) { if (Files.exists(file)) { try { - XMPUtil.writeXMP(file.toFile(), entry, database, Globals.prefs.getXMPPreferences()); + XmpUtilWriter.writeXmp(file, entry, database, Globals.prefs.getXMPPreferences()); SwingUtilities.invokeLater( () -> optDiag.getProgressArea().append(" " + Localization.lang("OK") + ".\n")); entriesChanged++; diff --git a/src/main/java/org/jabref/gui/fieldeditors/LinkedFileViewModel.java b/src/main/java/org/jabref/gui/fieldeditors/LinkedFileViewModel.java index 490ccaa05f3..6f44cec1c8b 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/LinkedFileViewModel.java +++ b/src/main/java/org/jabref/gui/fieldeditors/LinkedFileViewModel.java @@ -34,7 +34,7 @@ import org.jabref.logic.cleanup.RenamePdfCleanup; import org.jabref.logic.l10n.Localization; import org.jabref.logic.util.io.FileUtil; -import org.jabref.logic.xmp.XMPUtil; +import org.jabref.logic.xmp.XmpUtilWriter; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.LinkedFile; @@ -331,7 +331,7 @@ public void writeXMPMetadata() { // Localization.lang("PDF does not exist"); } else { try { - XMPUtil.writeXMP(file.get(), entry, databaseContext.getDatabase(), Globals.prefs.getXMPPreferences()); + XmpUtilWriter.writeXmp(file.get(), entry, databaseContext.getDatabase(), Globals.prefs.getXMPPreferences()); } catch (IOException | TransformerException ex) { // TODO: Print error message // Localization.lang("Error while writing") + " '" + file.toString() + "': " + ex; diff --git a/src/main/java/org/jabref/gui/importer/EntryFromPDFCreator.java b/src/main/java/org/jabref/gui/importer/EntryFromPDFCreator.java index e4f288970e2..250eca94991 100644 --- a/src/main/java/org/jabref/gui/importer/EntryFromPDFCreator.java +++ b/src/main/java/org/jabref/gui/importer/EntryFromPDFCreator.java @@ -1,28 +1,18 @@ package org.jabref.gui.importer; import java.io.File; -import java.io.IOException; -import java.time.LocalDate; -import java.time.format.DateTimeFormatter; -import java.util.Calendar; import java.util.Collections; -import java.util.List; import java.util.Locale; import java.util.Optional; -import org.jabref.Globals; import org.jabref.JabRefGUI; import org.jabref.gui.IconTheme; import org.jabref.gui.externalfiletype.ExternalFileType; import org.jabref.gui.externalfiletype.ExternalFileTypes; -import org.jabref.logic.xmp.XMPUtil; import org.jabref.model.entry.BibEntry; import org.jabref.pdfimport.PdfImporter; import org.jabref.pdfimport.PdfImporter.ImportPdfFilesResult; -import org.apache.pdfbox.pdmodel.PDDocument; -import org.apache.pdfbox.pdmodel.PDDocumentInformation; - /** * Uses XMPUtils to get one BibEntry for a PDF-File. * Also imports the non-XMP Data (PDDocument-Information) using XMPUtil.getBibtexEntryFromDocumentInformation. @@ -68,65 +58,6 @@ protected Optional createBibtexEntry(File pdfFile) { return Optional.empty(); } - /*addEntryDataFromPDDocumentInformation(pdfFile, entry); - addEntryDataFromXMP(pdfFile, entry); - - if (entry.getField(FieldName.TITLE) == null) { - entry.setField(FieldName.TITLE, pdfFile.getName()); - } - - return entry;*/ - } - - /** Adds entry data read from the PDDocument information of the file. - * @param pdfFile - * @param entry - */ - private void addEntryDataFromPDDocumentInformation(File pdfFile, BibEntry entry) { - try (PDDocument document = PDDocument.load(pdfFile.getAbsoluteFile())) { - PDDocumentInformation pdfDocInfo = document - .getDocumentInformation(); - - if (pdfDocInfo != null) { - Optional entryDI = XMPUtil - .getBibtexEntryFromDocumentInformation(document - .getDocumentInformation()); - if (entryDI.isPresent()) { - addEntryDataToEntry(entry, entryDI.get()); - Calendar creationDate = pdfDocInfo.getCreationDate(); - if (creationDate != null) { - // default time stamp follows ISO-8601. Reason: https://xkcd.com/1179/ - String date = LocalDate.of(Calendar.YEAR, Calendar.MONTH + 1, Calendar.DAY_OF_MONTH) - .format(DateTimeFormatter.ISO_LOCAL_DATE); - appendToField(entry, Globals.prefs.getTimestampPreferences().getTimestampField(), date); - } - - if (pdfDocInfo.getCustomMetadataValue("bibtex/bibtexkey") != null) { - entry.setId(pdfDocInfo - .getCustomMetadataValue("bibtex/bibtexkey")); - } - } - } - } catch (IOException e) { - // no canceling here, just no data added. - } - } - - /** - * Adds all data Found in all the entries of this XMP file to the given - * entry. This was implemented without having much knowledge of the XMP - * format. - * - * @param aFile - * @param entry - */ - private void addEntryDataFromXMP(File aFile, BibEntry entry) { - try { - List entrys = XMPUtil.readXMP(aFile.getAbsoluteFile(), Globals.prefs.getXMPPreferences()); - addEntrysToEntry(entry, entrys); - } catch (IOException e) { - // no canceling here, just no data added. - } } @Override diff --git a/src/main/java/org/jabref/logic/importer/ImportFormatReader.java b/src/main/java/org/jabref/logic/importer/ImportFormatReader.java index f3d5b9908d5..5d8b80b5704 100644 --- a/src/main/java/org/jabref/logic/importer/ImportFormatReader.java +++ b/src/main/java/org/jabref/logic/importer/ImportFormatReader.java @@ -29,7 +29,7 @@ import org.jabref.logic.importer.fileformat.RisImporter; import org.jabref.logic.importer.fileformat.SilverPlatterImporter; import org.jabref.logic.l10n.Localization; -import org.jabref.logic.xmp.XMPPreferences; +import org.jabref.logic.xmp.XmpPreferences; import org.jabref.model.database.BibDatabases; import org.jabref.model.entry.BibEntry; import org.jabref.model.strings.StringUtil; @@ -47,7 +47,7 @@ public class ImportFormatReader { private ImportFormatPreferences importFormatPreferences; - public void resetImportFormats(ImportFormatPreferences newImportFormatPreferences, XMPPreferences xmpPreferences, FileUpdateMonitor fileMonitor) { + public void resetImportFormats(ImportFormatPreferences newImportFormatPreferences, XmpPreferences xmpPreferences, FileUpdateMonitor fileMonitor) { this.importFormatPreferences = newImportFormatPreferences; formats.clear(); diff --git a/src/main/java/org/jabref/logic/importer/fileformat/PdfContentImporter.java b/src/main/java/org/jabref/logic/importer/fileformat/PdfContentImporter.java index 1c65c0b6a52..493d2b6a281 100644 --- a/src/main/java/org/jabref/logic/importer/fileformat/PdfContentImporter.java +++ b/src/main/java/org/jabref/logic/importer/fileformat/PdfContentImporter.java @@ -1,7 +1,6 @@ package org.jabref.logic.importer.fileformat; import java.io.BufferedReader; -import java.io.FileInputStream; import java.io.IOException; import java.io.StringWriter; import java.nio.charset.Charset; @@ -21,7 +20,7 @@ import org.jabref.logic.l10n.Localization; import org.jabref.logic.util.FileType; import org.jabref.logic.xmp.EncryptedPdfsNotSupportedException; -import org.jabref.logic.xmp.XMPUtil; +import org.jabref.logic.xmp.XmpUtilReader; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.BibtexEntryTypes; import org.jabref.model.entry.EntryType; @@ -30,7 +29,7 @@ import com.google.common.base.Strings; import org.apache.pdfbox.pdmodel.PDDocument; -import org.apache.pdfbox.util.PDFTextStripper; +import org.apache.pdfbox.text.PDFTextStripper; /** * PdfContentImporter parses data of the first page of the PDF and creates a BibTeX entry. @@ -205,8 +204,7 @@ public ParserResult importDatabase(String data) throws IOException { @Override public ParserResult importDatabase(Path filePath, Charset defaultEncoding) { final ArrayList result = new ArrayList<>(1); - try (FileInputStream fileStream = new FileInputStream(filePath.toFile()); - PDDocument document = XMPUtil.loadWithAutomaticDecryption(fileStream)) { + try (PDDocument document = XmpUtilReader.loadWithAutomaticDecryption(filePath)) { String firstPageContents = getFirstPageContents(document); Optional doi = DOI.findInText(firstPageContents); diff --git a/src/main/java/org/jabref/logic/importer/fileformat/PdfXmpImporter.java b/src/main/java/org/jabref/logic/importer/fileformat/PdfXmpImporter.java index 526766e3685..8ed231e1c21 100644 --- a/src/main/java/org/jabref/logic/importer/fileformat/PdfXmpImporter.java +++ b/src/main/java/org/jabref/logic/importer/fileformat/PdfXmpImporter.java @@ -10,18 +10,19 @@ import org.jabref.logic.importer.ParserResult; import org.jabref.logic.l10n.Localization; import org.jabref.logic.util.FileType; -import org.jabref.logic.xmp.XMPPreferences; -import org.jabref.logic.xmp.XMPUtil; +import org.jabref.logic.xmp.XmpPreferences; +import org.jabref.logic.xmp.XmpUtilReader; +import org.jabref.logic.xmp.XmpUtilShared; /** * Wraps the XMPUtility function to be used as an Importer. */ public class PdfXmpImporter extends Importer { - private final XMPPreferences xmpPreferences; + private final XmpPreferences xmpPreferences; - public PdfXmpImporter(XMPPreferences xmpPreferences) { + public PdfXmpImporter(XmpPreferences xmpPreferences) { this.xmpPreferences = xmpPreferences; } @@ -55,7 +56,7 @@ public ParserResult importDatabase(String data) throws IOException { public ParserResult importDatabase(Path filePath, Charset defaultEncoding) { Objects.requireNonNull(filePath); try { - return new ParserResult(XMPUtil.readXMP(filePath, xmpPreferences)); + return new ParserResult(XmpUtilReader.readXmp(filePath, xmpPreferences)); } catch (IOException exception) { return ParserResult.fromError(exception); } @@ -74,7 +75,7 @@ public boolean isRecognizedFormat(BufferedReader reader) throws IOException { @Override public boolean isRecognizedFormat(Path filePath, Charset defaultEncoding) throws IOException { Objects.requireNonNull(filePath); - return XMPUtil.hasMetadata(filePath, xmpPreferences); + return XmpUtilShared.hasMetadata(filePath, xmpPreferences); } @Override diff --git a/src/main/java/org/jabref/logic/pdf/PdfAnnotationImporter.java b/src/main/java/org/jabref/logic/pdf/PdfAnnotationImporter.java index 0f973f25afa..207bc2d31dd 100644 --- a/src/main/java/org/jabref/logic/pdf/PdfAnnotationImporter.java +++ b/src/main/java/org/jabref/logic/pdf/PdfAnnotationImporter.java @@ -18,6 +18,7 @@ import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPage; +import org.apache.pdfbox.pdmodel.PDPageTree; import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotation; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -41,10 +42,10 @@ public List importAnnotations(final Path path) { } List annotationsList = new LinkedList<>(); - try (PDDocument document = PDDocument.load(path.toString())) { - List pdfPages = document.getDocumentCatalog().getAllPages(); - for (int pageIndex = 0; pageIndex < pdfPages.size(); pageIndex++) { - PDPage page = (PDPage) pdfPages.get(pageIndex); + try (PDDocument document = PDDocument.load(path.toFile())) { + PDPageTree pdfPages = document.getDocumentCatalog().getPages(); + for (int pageIndex = 0; pageIndex < pdfPages.getCount(); pageIndex++) { + PDPage page = pdfPages.get(pageIndex); for (PDAnnotation annotation : page.getAnnotations()) { if (!isSupportedAnnotationType(annotation)) { continue; @@ -54,7 +55,7 @@ public List importAnnotations(final Path path) { annotationsList.add(createMarkedAnnotations(pageIndex, page, annotation)); } else { FileAnnotation fileAnnotation = new FileAnnotation(annotation, pageIndex + 1); - if (fileAnnotation.getContent() != null && !fileAnnotation.getContent().isEmpty()) { + if ((fileAnnotation.getContent() != null) && !fileAnnotation.getContent().isEmpty()) { annotationsList.add(fileAnnotation); } } @@ -86,12 +87,12 @@ private boolean isSupportedAnnotationType(PDAnnotation annotation) { private FileAnnotation createMarkedAnnotations(int pageIndex, PDPage page, PDAnnotation annotation) { FileAnnotation annotationBelongingToMarking = new FileAnnotation( - annotation.getDictionary().getString(COSName.T), FileAnnotation.extractModifiedTime(annotation.getModifiedDate()), + annotation.getCOSObject().getString(COSName.T), FileAnnotation.extractModifiedTime(annotation.getModifiedDate()), pageIndex + 1, annotation.getContents(), FileAnnotationType.valueOf(annotation.getSubtype().toUpperCase(Locale.ROOT)), Optional.empty()); if (annotationBelongingToMarking.getAnnotationType().isLinkedFileAnnotationType()) { try { - COSArray boundingBoxes = (COSArray) annotation.getDictionary().getDictionaryObject(COSName.getPDFName("QuadPoints")); + COSArray boundingBoxes = (COSArray) annotation.getCOSObject().getDictionaryObject(COSName.getPDFName("QuadPoints")); annotation.setContents(new TextExtractor(page, boundingBoxes).extractMarkedText()); } catch (IOException e) { annotation.setContents("JabRef: Could not extract any marked text!"); diff --git a/src/main/java/org/jabref/logic/pdf/TextExtractor.java b/src/main/java/org/jabref/logic/pdf/TextExtractor.java index 18ba03a9616..4d395360690 100644 --- a/src/main/java/org/jabref/logic/pdf/TextExtractor.java +++ b/src/main/java/org/jabref/logic/pdf/TextExtractor.java @@ -9,7 +9,7 @@ import org.apache.pdfbox.cos.COSInteger; import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.common.PDRectangle; -import org.apache.pdfbox.util.PDFTextStripperByArea; +import org.apache.pdfbox.text.PDFTextStripperByArea; /** * Extracts the text of marked annotations using bounding boxes. diff --git a/src/main/java/org/jabref/logic/xmp/DocumentInformationExtractor.java b/src/main/java/org/jabref/logic/xmp/DocumentInformationExtractor.java new file mode 100644 index 00000000000..04017fc8e1f --- /dev/null +++ b/src/main/java/org/jabref/logic/xmp/DocumentInformationExtractor.java @@ -0,0 +1,99 @@ +package org.jabref.logic.xmp; + +import java.util.Map; +import java.util.Optional; + +import org.jabref.model.entry.BibEntry; +import org.jabref.model.entry.FieldName; + +import org.apache.pdfbox.cos.COSBase; +import org.apache.pdfbox.cos.COSDictionary; +import org.apache.pdfbox.cos.COSName; +import org.apache.pdfbox.pdmodel.PDDocumentInformation; + +public class DocumentInformationExtractor { + + private final PDDocumentInformation documentInformation; + + private final BibEntry bibEntry; + + public DocumentInformationExtractor(PDDocumentInformation documentInformation) { + this.documentInformation = documentInformation; + + this.bibEntry = new BibEntry(); + } + + private void extractAuthor() { + String s = documentInformation.getAuthor(); + if (s != null) { + bibEntry.setField(FieldName.AUTHOR, s); + } + } + + private void extractTitle() { + String s = documentInformation.getTitle(); + if (s != null) { + bibEntry.setField(FieldName.TITLE, s); + } + } + + private void extractKeywords() { + String s = documentInformation.getKeywords(); + if (s != null) { + bibEntry.setField(FieldName.KEYWORDS, s); + } + } + + private void extractSubject() { + String s = documentInformation.getSubject(); + if (s != null) { + bibEntry.setField(FieldName.ABSTRACT, s); + } + } + + private void extractOtherFields() { + COSDictionary dict = documentInformation.getCOSObject(); + for (Map.Entry o : dict.entrySet()) { + String key = o.getKey().getName(); + if (key.startsWith("bibtex/")) { + String value = dict.getString(key); + key = key.substring("bibtex/".length()); + if (BibEntry.TYPE_HEADER.equals(key)) { + bibEntry.setType(value); + } else { + bibEntry.setField(key, value); + } + } + } + } + + /** + * Function for retrieving a BibEntry from the + * PDDocumentInformation in a PDF file. + * + * To understand how to get hold of a PDDocumentInformation have a look in + * the test cases for XMPUtilTest. + * + * The BibEntry is build by mapping individual fields in the document + * information (like author, title, keywords) to fields in a bibtex entry. + * + * @param di The document information from which to build a BibEntry. + * @return The bibtex entry found in the document information. + */ + public Optional extractBibtexEntry() { + + bibEntry.setType(BibEntry.DEFAULT_TYPE); + + this.extractAuthor(); + this.extractTitle(); + this.extractKeywords(); + this.extractSubject(); + this.extractOtherFields(); + + if (bibEntry.getFieldNames().isEmpty()) { + return Optional.empty(); + } else { + return Optional.of(bibEntry); + } + } +} diff --git a/src/main/java/org/jabref/logic/xmp/DublinCoreExtractor.java b/src/main/java/org/jabref/logic/xmp/DublinCoreExtractor.java new file mode 100644 index 00000000000..50964ab256f --- /dev/null +++ b/src/main/java/org/jabref/logic/xmp/DublinCoreExtractor.java @@ -0,0 +1,388 @@ +package org.jabref.logic.xmp; + +import java.io.IOException; +import java.util.Calendar; +import java.util.List; +import java.util.Map.Entry; +import java.util.Optional; +import java.util.Set; +import java.util.TreeSet; + +import org.jabref.logic.TypedBibEntry; +import org.jabref.model.database.BibDatabaseMode; +import org.jabref.model.entry.Author; +import org.jabref.model.entry.AuthorList; +import org.jabref.model.entry.BibEntry; +import org.jabref.model.entry.FieldName; +import org.jabref.model.entry.Month; +import org.jabref.model.strings.StringUtil; + +import com.microsoft.applicationinsights.agent.internal.common.StringUtils; +import org.apache.xmpbox.DateConverter; +import org.apache.xmpbox.schema.DublinCoreSchema; + +public class DublinCoreExtractor { + + private final DublinCoreSchema dcSchema; + private final XmpPreferences xmpPreferences; + + private final BibEntry bibEntry; + + public DublinCoreExtractor(DublinCoreSchema dcSchema, XmpPreferences xmpPreferences, BibEntry resolvedEntry) { + this.dcSchema = dcSchema; + this.xmpPreferences = xmpPreferences; + + this.bibEntry = resolvedEntry; + } + + /** + * Editor in BibTex - Contributor in DublinCore + * + * @param bibEntry The BibEntry object, which is filled during metadata extraction. + * @param dcSchema Metadata in DublinCore format. + */ + private void extractEditor() { + List contributors = dcSchema.getContributors(); + if ((contributors != null) && !contributors.isEmpty()) { + bibEntry.setField(FieldName.EDITOR, String.join(" and ", contributors)); + } + } + + /** + * Author in BibTex - Creator in DublinCore + * + * @param bibEntry The BibEntry object, which is filled during metadata extraction. + * @param dcSchema Metadata in DublinCore format. + */ + private void extractAuthor() { + List creators = dcSchema.getCreators(); + if ((creators != null) && !creators.isEmpty()) { + bibEntry.setField(FieldName.AUTHOR, String.join(" and ", creators)); + } + } + + /** + * Year + Month in BibTex - Date in DublinCore is a combination of year and month information + * + * @param bibEntry The BibEntry object, which is filled during metadata extraction. + * @param dcSchema Metadata in DublinCore format. + */ + private void extractYearAndMonth() { + List dates = dcSchema.getUnqualifiedSequenceValueList("date"); + if ((dates != null) && !dates.isEmpty()) { + String date = dates.get(0).trim(); + Calendar calender = null; + try { + calender = DateConverter.toCalendar(date); + } catch (IOException ignored) { + // Ignored + } + if (calender != null) { + bibEntry.setField(FieldName.YEAR, String.valueOf(calender.get(Calendar.YEAR))); + if (date.length() > 4) { + Optional month = Month.getMonthByNumber(calender.get(Calendar.MONTH) + 1); + month.ifPresent(bibEntry::setMonth); + } + } + } + } + + /** + * Abstract in BibTex - Description in DublinCore + * + * @param bibEntry The BibEntry object, which is filled during metadata extraction. + * @param dcSchema Metadata in DublinCore format. + */ + private void extractAbstract() { + String description = dcSchema.getDescription(); + if (!StringUtil.isNullOrEmpty(description)) { + bibEntry.setField(FieldName.ABSTRACT, description); + } + } + + /** + * DOI in BibTex - Identifier in DublinCore + * + * @param bibEntry The BibEntry object, which is filled during metadata extraction. + * @param dcSchema Metadata in DublinCore format. + */ + private void extractDOI() { + String identifier = dcSchema.getIdentifier(); + if (!StringUtils.isNullOrEmpty(identifier)) { + bibEntry.setField(FieldName.DOI, identifier); + } + } + + /** + * Publisher are equivalent in both formats (BibTex and DublinCore) + * + * @param bibEntry The BibEntry object, which is filled during metadata extraction. + * @param dcSchema Metadata in DublinCore format. + */ + private void extractPublisher() { + List publishers = dcSchema.getPublishers(); + if ((publishers != null) && !publishers.isEmpty()) { + bibEntry.setField(FieldName.PUBLISHER, String.join(" and ", publishers)); + } + } + + /** + * This method sets all fields, which are custom in bibtext and therefore supported by jabref, but which are not included in the DublinCore format. + *

+ * The relation attribute of DublinCore is abused to insert these custom fields. + * + * @param bibEntry The BibEntry object, which is filled during metadata extraction. + * @param dcSchema Metadata in DublinCore format. + */ + private void extractBibTexFields() { + List relationships = dcSchema.getRelations(); + if (relationships != null) { + for (String r : relationships) { + if (r.startsWith("bibtex/")) { + r = r.substring("bibtex/".length()); + int i = r.indexOf('/'); + if (i != -1) { + bibEntry.setField(r.substring(0, i), r.substring(i + 1)); + } + } + } + } + } + + /** + * Rights are equivalent in both formats (BibTex and DublinCore) + * + * @param bibEntry The BibEntry object, which is filled during metadata extraction. + * @param dcSchema Metadata in DublinCore format. + */ + private void extractRights() { + String rights = dcSchema.getRights(); + if (!StringUtils.isNullOrEmpty(rights)) { + bibEntry.setField("rights", rights); + } + } + + /** + * Source is equivalent in both formats (BibTex and DublinCore) + * + * @param bibEntry The BibEntry object, which is filled during metadata extraction. + * @param dcSchema Metadata in DublinCore format. + */ + private void extractSource() { + String source = dcSchema.getSource(); + if (!StringUtils.isNullOrEmpty(source)) { + bibEntry.setField("source", source); + } + } + + /** + * Keywords in BibTex - Subjects in DublinCore + * @param bibEntry The BibEntry object, which is filled during metadata extraction. + * @param dcSchema Metadata in DublinCore format. + */ + private void extractSubject() { + List subjects = dcSchema.getSubjects(); + if ((subjects != null) && !subjects.isEmpty()) { + bibEntry.addKeywords(subjects, xmpPreferences.getKeywordSeparator()); + } + } + + /** + * Title is equivalent in both formats (BibTex and DublinCore) + * + * @param bibEntry The BibEntry object, which is filled during metadata extraction. + * @param dcSchema Metadata in DublinCore format. + */ + private void extractTitle() { + String title = dcSchema.getTitle(); + if (!StringUtil.isNullOrEmpty(title)) { + bibEntry.setField(FieldName.TITLE, title); + } + } + + /** + * Type is equivalent in both formats (BibTex and DublinCore) + * + * @param bibEntry The BibEntry object, which is filled during metadata extraction. + * @param dcSchema Metadata in DublinCore format. + */ + private void extractType() { + List types = dcSchema.getTypes(); + if ((types != null) && !types.isEmpty()) { + String type = types.get(0); + if (!StringUtils.isNullOrEmpty(type)) { + bibEntry.setType(type); + } + } + } + + /** + * Helper function for retrieving a BibEntry from the DublinCore metadata + * in a PDF file. + * + * To understand how to get hold of a DublinCore have a look in the + * test cases for XMPUtil. + * + * The BibEntry is build by mapping individual fields in the dublin core + * (like creator, title, subject) to fields in a bibtex bibEntry. + * + * @param dcSchema The document information from which to build a BibEntry. + * @return The bibtex bibEntry found in the document information. + */ + public Optional extractBibtexEntry() { + + this.extractEditor(); + this.extractAuthor(); + this.extractYearAndMonth(); + this.extractAbstract(); + this.extractDOI(); + this.extractPublisher(); + this.extractBibTexFields(); + this.extractRights(); + this.extractSource(); + this.extractSubject(); + this.extractTitle(); + this.extractType(); + + if (bibEntry.getType() == null) { + bibEntry.setType(BibEntry.DEFAULT_TYPE); + } + + return Optional.of(bibEntry); + } + + /** + * Bibtex-Fields used: editor, Field: 'dc:contributor' + * + * @param authors + */ + private void fillContributor(String authors) { + AuthorList list = AuthorList.parse(authors); + for (Author author : list.getAuthors()) { + dcSchema.addContributor(author.getFirstLast(false)); + } + } + + /** + * Bibtex-Fields used: author, Field: 'dc:creator' + * + * @param creators + */ + private void fillCreator(String creators) { + AuthorList list = AuthorList.parse(creators); + + for (Author author : list.getAuthors()) { + dcSchema.addCreator(author.getFirstLast(false)); + } + } + + /** + * Bibtex-Fields used: year, month, Field: 'dc:date' + */ + private void fillDate() { + bibEntry.getFieldOrAlias(FieldName.DATE) + .ifPresent(publicationDate -> dcSchema.addUnqualifiedSequenceValue("date", publicationDate)); + } + + /** + * Bibtex-Fields used: abstract, Field: 'dc:description' + * + * @param description + */ + private void fillDescription(String description) { + dcSchema.setDescription(description); + } + + /** + * Bibtex-Fields used: doi, Field: 'dc:identifier' + * + * @param identifier + */ + private void fillIdentifier(String identifier) { + dcSchema.setIdentifier(identifier); + } + + /** + * Bibtex-Fields used: publisher, Field: dc:publisher + * + * @param publisher + */ + private void fillPublisher(String publisher) { + dcSchema.addPublisher(publisher); + } + + /** + * Bibtex-Fields used: keywords, Field: 'dc:subject' + * + * @param value + */ + private void fillKeywords(String value) { + String[] keywords = value.split(","); + for (String keyword : keywords) { + dcSchema.addSubject(keyword.trim()); + } + } + + /** + * Bibtex-Fields used: title, Field: 'dc:title' + * + * @param title + */ + private void fillTitle(String title) { + dcSchema.setTitle(title); + } + + /** + * All others (+ bibtex key) get packaged in the relation attribute + * + * @param key Key of the metadata attribute + * @param value Value of the metadata attribute + */ + private void fillCustomField(String key, String value) { + dcSchema.addRelation("bibtex/" + key + '/' + value); + } + + public void fillDublinCoreSchema() { + + // Query privacy filter settings + boolean useXmpPrivacyFilter = xmpPreferences.isUseXMPPrivacyFilter(); + // Fields for which not to write XMP data later on: + Set filters = new TreeSet<>(xmpPreferences.getXmpPrivacyFilter()); + + for (Entry field : bibEntry.getFieldMap().entrySet()) { + + if (useXmpPrivacyFilter && filters.contains(field.getKey())) { + continue; + } + + if (FieldName.EDITOR.equals(field.getKey())) { + this.fillContributor(field.getValue()); + } else if (FieldName.AUTHOR.equals(field.getKey())) { + this.fillCreator(field.getValue()); + } else if (FieldName.YEAR.equals(field.getKey())) { + this.fillDate(); + } else if (FieldName.ABSTRACT.equals(field.getKey())) { + this.fillDescription(field.getValue()); + } else if (FieldName.DOI.equals(field.getKey())) { + this.fillIdentifier(field.getValue()); + } else if (FieldName.PUBLISHER.equals(field.getKey())) { + this.fillPublisher(field.getValue()); + } else if (FieldName.KEYWORDS.equals(field.getKey())) { + this.fillKeywords(field.getValue()); + } else if (FieldName.TITLE.equals(field.getKey())) { + this.fillTitle(field.getValue()); + } else { + this.fillCustomField(field.getKey(), field.getValue()); + } + } + + dcSchema.setFormat("application/pdf"); + + // Bibtex-Fields used: entrytype, Field: 'dc:type' + TypedBibEntry typedEntry = new TypedBibEntry(bibEntry, BibDatabaseMode.BIBTEX); + String o = typedEntry.getTypeForDisplay(); + if (!o.isEmpty()) { + dcSchema.addType(o); + } + } +} diff --git a/src/main/java/org/jabref/logic/xmp/XMPSchemaBibtex.java b/src/main/java/org/jabref/logic/xmp/XMPSchemaBibtex.java deleted file mode 100644 index 757ab8b9779..00000000000 --- a/src/main/java/org/jabref/logic/xmp/XMPSchemaBibtex.java +++ /dev/null @@ -1,324 +0,0 @@ -package org.jabref.logic.xmp; - -import java.io.IOException; -import java.util.Calendar; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.TreeSet; - -import javax.xml.transform.TransformerException; - -import org.jabref.model.database.BibDatabase; -import org.jabref.model.entry.Author; -import org.jabref.model.entry.AuthorList; -import org.jabref.model.entry.BibEntry; -import org.jabref.model.entry.FieldName; -import org.jabref.model.entry.FieldProperty; -import org.jabref.model.entry.InternalBibtexFields; - -import org.apache.jempbox.xmp.XMPMetadata; -import org.apache.jempbox.xmp.XMPSchema; -import org.w3c.dom.Element; -import org.w3c.dom.NamedNodeMap; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; - -public class XMPSchemaBibtex extends XMPSchema { - - /** - * The namespace of this schema. - */ - public static final String NAMESPACE = "http://jabref.sourceforge.net/bibteXMP/"; - - private static final String KEY = "bibtex"; - - private static final Set PRESERVE_WHITE_SPACE = new HashSet<>(); - - static { - XMPSchemaBibtex.PRESERVE_WHITE_SPACE.add(FieldName.ABSTRACT); - XMPSchemaBibtex.PRESERVE_WHITE_SPACE.add(FieldName.NOTE); - XMPSchemaBibtex.PRESERVE_WHITE_SPACE.add(FieldName.REVIEW); - } - - /** - * Create a new empty XMPSchemaBibtex as a child in the given XMPMetadata. - * - * @param parent - */ - public XMPSchemaBibtex(XMPMetadata parent) { - super(parent, XMPSchemaBibtex.KEY, XMPSchemaBibtex.NAMESPACE); - } - - /** - * Create schema from an existing XML element. - * - * @param e - * The existing XML element. - * @param namespace - * The name space considered. Must currently be there for compatibility reasons despite being unused. - */ - public XMPSchemaBibtex(Element e, @SuppressWarnings("unused") String namespace) { - super(e, XMPSchemaBibtex.KEY); - } - - private static String makeProperty(String propertyName) { - return XMPSchemaBibtex.KEY + ':' + propertyName; - } - - /** - * Uses XMPSchema methods - * - * @param field - * @return - */ - public List getPersonList(String field) { - return getSequenceList(field); - } - - /** - * Uses XMPSchema methods - * - * @param field - * @param value - */ - public void setPersonList(String field, String value) { - AuthorList list = AuthorList.parse(value); - - for (Author author : list.getAuthors()) { - addSequenceValue(field, author.getFirstLast(false)); - } - } - - @Override - public String getTextProperty(String field) { - return super.getTextProperty(makeProperty(field)); - } - - @Override - public void setTextProperty(String field, String value) { - super.setTextProperty(makeProperty(field), value); - } - - @Override - public List getBagList(String bagName) { - return super.getBagList(makeProperty(bagName)); - } - - @Override - public void removeBagValue(String bagName, String value) { - super.removeBagValue(makeProperty(bagName), value); - } - - @Override - public void addBagValue(String bagName, String value) { - super.addBagValue(makeProperty(bagName), value); - } - - @Override - public List getSequenceList(String seqName) { - return super.getSequenceList(makeProperty(seqName)); - } - - @Override - public void removeSequenceValue(String seqName, String value) { - super.removeSequenceValue(makeProperty(seqName), value); - } - - @Override - public void addSequenceValue(String seqName, String value) { - super.addSequenceValue(makeProperty(seqName), value); - } - - @Override - public List getSequenceDateList(String seqName) throws IOException { - return super.getSequenceDateList(makeProperty(seqName)); - } - - @Override - public void removeSequenceDateValue(String seqName, Calendar date) { - super.removeSequenceDateValue(makeProperty(seqName), date); - } - - @Override - public void addSequenceDateValue(String field, Calendar date) { - super.addSequenceDateValue(makeProperty(field), date); - } - - private static String getContents(NodeList seqList) { - - Element seqNode = (Element) seqList.item(0); - StringBuilder seq = null; - - NodeList items = seqNode.getElementsByTagName("rdf:li"); - for (int j = 0; j < items.getLength(); j++) { - Element li = (Element) items.item(j); - if (seq == null) { - seq = new StringBuilder(); - } else { - seq.append(" and "); - } - seq.append(XMPSchemaBibtex.getTextContent(li)); - } - if (seq != null) { - return seq.toString(); - } - return null; - } - - /** - * Returns a map of all properties and their values. LIs and bags in seqs - * are concatenated using " and ". - * - * @return Map from name of textproperty (String) to value (String). For - * instance: "year" => "2005". Empty map if none found. - * @throws TransformerException - */ - public static Map getAllProperties(XMPSchema schema, String namespaceName) { - NodeList nodes = schema.getElement().getChildNodes(); - - Map result = new HashMap<>(); - - if (nodes == null) { - return result; - } - - // Check child-nodes first - int n = nodes.getLength(); - - for (int i = 0; i < n; i++) { - Node node = nodes.item(i); - if ((node.getNodeType() != Node.ATTRIBUTE_NODE) - && (node.getNodeType() != Node.ELEMENT_NODE)) { - continue; - } - - String nodeName = node.getNodeName(); - - String[] split = nodeName.split(":"); - - if ((split.length == 2) && split[0].equals(namespaceName)) { - NodeList seqList = ((Element) node).getElementsByTagName("rdf:Seq"); - if (seqList.getLength() > 0) { - - String seq = XMPSchemaBibtex.getContents(seqList); - - if (seq != null) { - result.put(split[1], seq); - } - } else { - NodeList bagList = ((Element) node).getElementsByTagName("rdf:Bag"); - if (bagList.getLength() > 0) { - - String seq = XMPSchemaBibtex.getContents(bagList); - - if (seq != null) { - result.put(split[1], seq); - } - } else { - result.put(split[1], XMPSchemaBibtex.getTextContent(node)); - } - } - } - } - - // Then check Attributes - NamedNodeMap attrs = schema.getElement().getAttributes(); - int m = attrs.getLength(); - for (int j = 0; j < m; j++) { - Node attr = attrs.item(j); - - String nodeName = attr.getNodeName(); - String[] split = nodeName.split(":"); - if ((split.length == 2) && split[0].equals(namespaceName)) { - result.put(split[1], attr.getNodeValue()); - } - } - - /* - * Collapse Whitespace - * - * Quoting from - * http://www.gerg.ca/software/btOOL/doc/bt_postprocess.html: - * "The exact rules for collapsing whitespace are simple: non-space - * whitespace characters (tabs and newlines mainly) are converted to - * space, any strings of more than one space within are collapsed to a - * single space, and any leading or trailing spaces are deleted." - * - */ - - for (Map.Entry entry : result.entrySet()) { - String key = entry.getKey(); - if (XMPSchemaBibtex.PRESERVE_WHITE_SPACE.contains(key)) { - continue; - } - entry.setValue(entry.getValue().replaceAll("\\s+", " ").trim()); - } - - return result; - } - - public void setBibtexEntry(BibEntry entry, XMPPreferences xmpPreferences) { - setBibtexEntry(entry, null, xmpPreferences); - } - - /** - * - * @param entry - * @param database maybenull - */ - public void setBibtexEntry(BibEntry entry, BibDatabase database, XMPPreferences xmpPreferences) { - // Set all the values including key and entryType - Set fields = entry.getFieldNames(); - - if ((xmpPreferences != null) && xmpPreferences.isUseXMPPrivacyFilter()) { - Set filters = new TreeSet<>(xmpPreferences.getXmpPrivacyFilter()); - fields.removeAll(filters); - } - - for (String field : fields) { - String value = entry.getResolvedFieldOrAlias(field, database).orElse(""); - if (InternalBibtexFields.getFieldProperties(field).contains(FieldProperty.PERSON_NAMES)) { - setPersonList(field, value); - } else { - setTextProperty(field, value); - } - } - setTextProperty(BibEntry.TYPE_HEADER, entry.getType()); - } - - public BibEntry getBibtexEntry() { - String type = getTextProperty(BibEntry.TYPE_HEADER); - BibEntry e = new BibEntry(type); - - // Get Text Properties - Map text = XMPSchemaBibtex.getAllProperties(this, "bibtex"); - text.remove(BibEntry.TYPE_HEADER); - e.setField(text); - return e; - } - - /** - * Taken from DOM2Utils.java: - * - * JBoss, the OpenSource EJB server - * - * Distributable under LGPL license. See terms of license at gnu.org. - */ - public static String getTextContent(Node node) { - boolean hasTextContent = false; - StringBuilder buffer = new StringBuilder(); - NodeList nlist = node.getChildNodes(); - for (int i = 0; i < nlist.getLength(); i++) { - Node child = nlist.item(i); - if (child.getNodeType() == Node.TEXT_NODE) { - buffer.append(child.getNodeValue()); - hasTextContent = true; - } - } - return hasTextContent ? buffer.toString() : ""; - } - -} diff --git a/src/main/java/org/jabref/logic/xmp/XMPUtil.java b/src/main/java/org/jabref/logic/xmp/XMPUtil.java deleted file mode 100644 index 97be1498ec9..00000000000 --- a/src/main/java/org/jabref/logic/xmp/XMPUtil.java +++ /dev/null @@ -1,1063 +0,0 @@ -package org.jabref.logic.xmp; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.StandardOpenOption; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Collection; -import java.util.Collections; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Optional; -import java.util.Set; -import java.util.TreeSet; - -import javax.xml.transform.TransformerException; - -import org.jabref.logic.TypedBibEntry; -import org.jabref.model.database.BibDatabase; -import org.jabref.model.database.BibDatabaseMode; -import org.jabref.model.entry.Author; -import org.jabref.model.entry.AuthorList; -import org.jabref.model.entry.BibEntry; -import org.jabref.model.entry.FieldName; -import org.jabref.model.entry.Month; -import org.jabref.model.strings.StringUtil; - -import org.apache.jempbox.impl.DateConverter; -import org.apache.jempbox.impl.XMLUtil; -import org.apache.jempbox.xmp.XMPMetadata; -import org.apache.jempbox.xmp.XMPSchema; -import org.apache.jempbox.xmp.XMPSchemaDublinCore; -import org.apache.pdfbox.cos.COSBase; -import org.apache.pdfbox.cos.COSDictionary; -import org.apache.pdfbox.cos.COSName; -import org.apache.pdfbox.exceptions.COSVisitorException; -import org.apache.pdfbox.exceptions.CryptographyException; -import org.apache.pdfbox.pdmodel.PDDocument; -import org.apache.pdfbox.pdmodel.PDDocumentCatalog; -import org.apache.pdfbox.pdmodel.PDDocumentInformation; -import org.apache.pdfbox.pdmodel.common.PDMetadata; -import org.apache.pdfbox.pdmodel.encryption.BadSecurityHandlerException; -import org.apache.pdfbox.pdmodel.encryption.StandardDecryptionMaterial; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.w3c.dom.Document; - -/** - * XMPUtils provide support for reading and writing BibTex data as XMP-Metadata - * in PDF-documents. - */ -public class XMPUtil { - - private static final Logger LOGGER = LoggerFactory.getLogger(XMPUtil.class); - - private XMPUtil() { - } - - /** - * Convenience method for readXMP(File). - * - * @param filename The filename from which to open the file. - * @return BibtexEntryies found in the PDF or an empty list - */ - public static List readXMP(String filename, XMPPreferences xmpPreferences) throws IOException { - return XMPUtil.readXMP(new File(filename), xmpPreferences); - } - - /** - * Try to write the given BibTexEntry in the XMP-stream of the given - * PDF-file. - * - * Throws an IOException if the file cannot be read or written, so the user - * can remove a lock or cancel the operation. - * - * The method will overwrite existing BibTeX-XMP-data, but keep other - * existing metadata. - * - * This is a convenience method for writeXMP(File, BibEntry). - * - * @param filename The filename from which to open the file. - * @param entry The entry to write. - * @param database maybenull An optional database which the given bibtex entries belong to, which will be used to - * resolve strings. If the database is null the strings will not be resolved. - * @throws TransformerException If the entry was malformed or unsupported. - * @throws IOException If the file could not be written to or could not be found. - */ - public static void writeXMP(String fileName, BibEntry entry, - BibDatabase database, XMPPreferences xmpPreferences) throws IOException, TransformerException { - XMPUtil.writeXMP(new File(fileName), entry, database, xmpPreferences); - } - - /** - * Try to read the BibTexEntries from the XMP-stream of the given PDF-file. - * - * @param file The file to read from. - * @throws IOException Throws an IOException if the file cannot be read, so the user than remove a lock or cancel - * the operation. - */ - public static List readXMP(File file, XMPPreferences xmpPreferences) throws IOException { - List result = Collections.emptyList(); - try (FileInputStream inputStream = new FileInputStream(file)) { - result = XMPUtil.readXMP(inputStream, xmpPreferences); - } - return result; - } - - public static PDDocument loadWithAutomaticDecryption(InputStream inputStream) throws IOException { - PDDocument doc = PDDocument.load(inputStream); - - if (doc.isEncrypted()) { - // try the empty string as user password - StandardDecryptionMaterial sdm = new StandardDecryptionMaterial(""); - try { - doc.openProtection(sdm); - } catch (BadSecurityHandlerException | CryptographyException e) { - LOGGER.error("Cannot handle encrypted PDF: " + e.getMessage()); - throw new EncryptedPdfsNotSupportedException(); - } - } - return doc; - } - - /** - * Try to read the given BibTexEntry from the XMP-stream of the given - * inputstream containing a PDF-file. - * - * @param inputStream The inputstream to read from. - * @return list of BibEntries retrieved from the stream. May be empty, but never null - * @throws IOException Throws an IOException if the file cannot be read, so the user than remove a lock or cancel - * the operation. - */ - public static List readXMP(InputStream inputStream, XMPPreferences xmpPreferences) - throws IOException { - - List result = new LinkedList<>(); - - try (PDDocument document = loadWithAutomaticDecryption(inputStream)) { - Optional meta = XMPUtil.getXMPMetadata(document); - - if (meta.isPresent()) { - - List schemas = meta.get().getSchemasByNamespaceURI(XMPSchemaBibtex.NAMESPACE); - - for (XMPSchema schema : schemas) { - XMPSchemaBibtex bib = (XMPSchemaBibtex) schema; - - BibEntry entry = bib.getBibtexEntry(); - if (entry.getType() == null) { - entry.setType(BibEntry.DEFAULT_TYPE); - } - result.add(entry); - } - - // If we did not find anything have a look if a Dublin Core exists - if (result.isEmpty()) { - schemas = meta.get().getSchemasByNamespaceURI(XMPSchemaDublinCore.NAMESPACE); - for (XMPSchema schema : schemas) { - XMPSchemaDublinCore dc = (XMPSchemaDublinCore) schema; - - Optional entry = XMPUtil.getBibtexEntryFromDublinCore(dc, - xmpPreferences); - - if (entry.isPresent()) { - if (entry.get().getType() == null) { - entry.get().setType(BibEntry.DEFAULT_TYPE); - } - result.add(entry.get()); - } - } - } - } - if (result.isEmpty()) { - // If we did not find any XMP metadata, search for non XMP metadata - PDDocumentInformation documentInformation = document.getDocumentInformation(); - Optional entry = XMPUtil.getBibtexEntryFromDocumentInformation(documentInformation); - entry.ifPresent(result::add); - } - } - - // return empty list, if no metadata was found - if (result.isEmpty()) { - return Collections.emptyList(); - } - return result; - } - - public static Collection readXMP(Path filePath, XMPPreferences xmpPreferences) throws IOException { - return readXMP(filePath.toFile(), xmpPreferences); - } - - /** - * Helper function for retrieving a BibEntry from the - * PDDocumentInformation in a PDF file. - * - * To understand how to get hold of a PDDocumentInformation have a look in - * the test cases for XMPUtil. - * - * The BibEntry is build by mapping individual fields in the document - * information (like author, title, keywords) to fields in a bibtex entry. - * - * @param di The document information from which to build a BibEntry. - * @return The bibtex entry found in the document information. - */ - public static Optional getBibtexEntryFromDocumentInformation( - PDDocumentInformation di) { - - BibEntry entry = new BibEntry(); - entry.setType(BibEntry.DEFAULT_TYPE); - - String s = di.getAuthor(); - if (s != null) { - entry.setField(FieldName.AUTHOR, s); - } - - s = di.getTitle(); - if (s != null) { - entry.setField(FieldName.TITLE, s); - } - - s = di.getKeywords(); - if (s != null) { - entry.setField(FieldName.KEYWORDS, s); - } - - s = di.getSubject(); - if (s != null) { - entry.setField(FieldName.ABSTRACT, s); - } - - COSDictionary dict = di.getDictionary(); - for (Map.Entry o : dict.entrySet()) { - String key = o.getKey().getName(); - if (key.startsWith("bibtex/")) { - String value = dict.getString(key); - key = key.substring("bibtex/".length()); - if (BibEntry.TYPE_HEADER.equals(key)) { - entry.setType(value); - } else { - entry.setField(key, value); - } - } - } - - // Return empty Optional if no values were found - return entry.getFieldNames().isEmpty() ? Optional.empty() : Optional.of(entry); - } - - /** - * Helper function for retrieving a BibEntry from the DublinCore metadata - * in a PDF file. - * - * To understand how to get hold of a XMPSchemaDublinCore have a look in the - * test cases for XMPUtil. - * - * The BibEntry is build by mapping individual fields in the dublin core - * (like creator, title, subject) to fields in a bibtex entry. - * - * @param dcSchema The document information from which to build a BibEntry. - * @return The bibtex entry found in the document information. - */ - public static Optional getBibtexEntryFromDublinCore(XMPSchemaDublinCore dcSchema, - XMPPreferences xmpPreferences) { - - BibEntry entry = new BibEntry(); - - /* - * Contributor -> Editor - */ - List contributors = dcSchema.getContributors(); - if ((contributors != null) && !contributors.isEmpty()) { - entry.setField(FieldName.EDITOR, String.join(" and ", contributors)); - } - - /* - * Author -> Creator - */ - List creators = dcSchema.getCreators(); - if ((creators != null) && !creators.isEmpty()) { - entry.setField(FieldName.AUTHOR, String.join(" and ", creators)); - } - - /* - * Year + Month -> Date - */ - List dates = dcSchema.getSequenceList("dc:date"); - if ((dates != null) && !dates.isEmpty()) { - String date = dates.get(0).trim(); - Calendar c = null; - try { - c = DateConverter.toCalendar(date); - } catch (IOException ignored) { - // Ignored - } - if (c != null) { - entry.setField(FieldName.YEAR, String.valueOf(c.get(Calendar.YEAR))); - if (date.length() > 4) { - Optional month = Month.getMonthByNumber(c.get(Calendar.MONTH) + 1); - month.ifPresent(entry::setMonth); - } - } - } - - /* - * Abstract -> Description - */ - String s = dcSchema.getDescription(); - if (s != null) { - entry.setField(FieldName.ABSTRACT, s); - } - - /* - * Identifier -> DOI - */ - s = dcSchema.getIdentifier(); - if (s != null) { - entry.setField(FieldName.DOI, s); - } - - /* - * Publisher -> Publisher - */ - List publishers = dcSchema.getPublishers(); - if ((publishers != null) && !publishers.isEmpty()) { - entry.setField(FieldName.PUBLISHER, String.join(" and ", publishers)); - } - - /* - * Relation -> bibtexkey - * - * We abuse the relationship attribute to store all other values in the - * bibtex document - */ - List relationships = dcSchema.getRelationships(); - if (relationships != null) { - for (String r : relationships) { - if (r.startsWith("bibtex/")) { - r = r.substring("bibtex/".length()); - int i = r.indexOf('/'); - if (i != -1) { - entry.setField(r.substring(0, i), r.substring(i + 1)); - } - } - } - } - - /* - * Rights -> Rights - */ - s = dcSchema.getRights(); - if (s != null) { - entry.setField("rights", s); - } - - /* - * Source -> Source - */ - s = dcSchema.getSource(); - if (s != null) { - entry.setField("source", s); - } - - /* - * Subject -> Keywords - */ - List subjects = dcSchema.getSubjects(); - if (subjects != null) { - entry.addKeywords(subjects, xmpPreferences.getKeywordSeparator()); - } - - /* - * Title -> Title - */ - s = dcSchema.getTitle(); - if (s != null) { - entry.setField(FieldName.TITLE, s); - } - - /* - * Type -> Type - */ - List l = dcSchema.getTypes(); - if ((l != null) && !l.isEmpty()) { - s = l.get(0); - if (s != null) { - entry.setType(s); - } - } - - return entry.getFieldNames().isEmpty() ? Optional.empty() : Optional.of(entry); - } - - /** - * Try to write the given BibTexEntry in the XMP-stream of the given - * PDF-file. - * - * Throws an IOException if the file cannot be read or written, so the user - * can remove a lock or cancel the operation. - * - * The method will overwrite existing BibTeX-XMP-data, but keep other - * existing metadata. - * - * This is a convenience method for writeXMP(File, Collection). - * - * @param file The file to write to. - * @param entry The entry to write. - * @param database maybenull An optional database which the given bibtex entries belong to, which will be used to - * resolve strings. If the database is null the strings will not be resolved. - * @throws TransformerException If the entry was malformed or unsupported. - * @throws IOException If the file could not be written to or could not be found. - * @deprecated use overlood {@link #writeXMP(Path, BibEntry, BibDatabase, XMPPreferences)} instead - */ - @Deprecated - public static void writeXMP(File file, BibEntry entry, - BibDatabase database, XMPPreferences xmpPreferences) throws IOException, TransformerException { - List l = new LinkedList<>(); - l.add(entry); - XMPUtil.writeXMP(file, l, database, true, xmpPreferences); - } - - public static void writeXMP(Path file, BibEntry entry, - BibDatabase database, XMPPreferences xmpPreferences) throws IOException, TransformerException { - writeXMP(file.toFile(), entry, database, xmpPreferences); - } - - /** - * Write the given BibtexEntries as XMP-metadata text to the given stream. - * - * The text that is written to the stream contains a complete XMP-document. - * - * @param bibtexEntries The BibtexEntries to write XMP-metadata for. - * @param database maybenull An optional database which the given bibtex entries belong to, which will be used - * to resolve strings. If the database is null the strings will not be resolved. - * @throws TransformerException Thrown if the bibtexEntries could not transformed to XMP. - * @throws IOException Thrown if an IOException occured while writing to the stream. - * @see #toXMP(java.util.Collection, BibDatabase) if you don't need strings to be resolved. - */ - private static void toXMP(Collection bibtexEntries, - BibDatabase database, OutputStream outputStream, XMPPreferences xmpPreferences) - throws IOException, TransformerException { - - Collection resolvedEntries; - if (database == null) { - resolvedEntries = bibtexEntries; - } else { - resolvedEntries = database.resolveForStrings(bibtexEntries, true); - } - - XMPMetadata x = new XMPMetadata(); - - for (BibEntry e : resolvedEntries) { - XMPSchemaBibtex schema = new XMPSchemaBibtex(x); - x.addSchema(schema); - schema.setBibtexEntry(e, xmpPreferences); - } - - x.save(outputStream); - } - - /** - * Convenience method for toXMP(Collection, BibDatabase, - * OutputStream) returning a String containing the XMP-metadata of the given - * collection of BibtexEntries. - * - * The resulting metadata string is wrapped as a complete XMP-document. - * - * @param bibtexEntries The BibtexEntries to return XMP-metadata for. - * @param database An optional database which the given bibtex entries belong to, which will be used - * to resolve strings. If the database is null the strings will not be resolved. - * @return The XMP representation of the given bibtexEntries. - * @throws TransformerException Thrown if the bibtexEntries could not transformed to XMP. - */ - public static String toXMP(Collection bibtexEntries, - BibDatabase database, XMPPreferences xmpPreferences) throws TransformerException { - try { - ByteArrayOutputStream bs = new ByteArrayOutputStream(); - XMPUtil.toXMP(bibtexEntries, database, bs, xmpPreferences); - return bs.toString(); - } catch (IOException e) { - throw new TransformerException(e); - } - } - - /** - * Will read the XMPMetadata from the given pdf file, closing the file - * afterwards. - * - * @param inputStream The inputStream representing a PDF-file to read the XMPMetadata from. - * @return The XMPMetadata object found in the file - */ - private static Optional readRawXMP(InputStream inputStream) throws IOException { - try (PDDocument document = loadWithAutomaticDecryption(inputStream)) { - return XMPUtil.getXMPMetadata(document); - } - } - - /** - * @return empty Optional if no metadata has been found - */ - private static Optional getXMPMetadata(PDDocument document) throws IOException { - PDDocumentCatalog catalog = document.getDocumentCatalog(); - PDMetadata metaRaw = catalog.getMetadata(); - - if (metaRaw == null) { - return Optional.empty(); - } - - Document parseResult; - try (InputStream is = metaRaw.createInputStream()) { - parseResult = XMLUtil.parse(is); - } - XMPMetadata meta = new XMPMetadata(parseResult); - meta.addXMLNSMapping(XMPSchemaBibtex.NAMESPACE, XMPSchemaBibtex.class); - return Optional.of(meta); - } - - /** - * Will read the XMPMetadata from the given pdf file, closing the file - * afterwards. - * - * @param file The file to read the XMPMetadata from. - * @return The XMPMetadata object found in the file - */ - public static Optional readRawXMP(File file) throws IOException { - try (FileInputStream inputStream = new FileInputStream(file)) { - return XMPUtil.readRawXMP(inputStream); - } - } - - private static void writeToDCSchema(XMPSchemaDublinCore dcSchema, BibEntry entry, BibDatabase database, - XMPPreferences xmpPreferences) { - - BibEntry resolvedEntry; - if (database == null) { - resolvedEntry = entry; - } else { - resolvedEntry = database.resolveForStrings(entry, false); - } - - // Query privacy filter settings - boolean useXmpPrivacyFilter = xmpPreferences.isUseXMPPrivacyFilter(); - // Fields for which not to write XMP data later on: - Set filters = new TreeSet<>(xmpPreferences.getXmpPrivacyFilter()); - - // Set all the values including key and entryType - - for (Entry field : resolvedEntry.getFieldMap().entrySet()) { - - if (useXmpPrivacyFilter && filters.contains(field.getKey())) { - continue; - } - - if (FieldName.EDITOR.equals(field.getKey())) { - String authors = field.getValue(); - - /* - * Editor -> Contributor - * - * Field: dc:contributor - * - * Type: bag ProperName - * - * Category: External - * - * Description: Contributors to the resource (other than the - * authors). - * - * Bibtex-Fields used: editor - */ - - AuthorList list = AuthorList.parse(authors); - - for (Author author : list.getAuthors()) { - dcSchema.addContributor(author.getFirstLast(false)); - } - continue; - } - - /* - * ? -> Coverage - * - * Unmapped - * - * dc:coverage Text External The extent or scope of the resource. - * - * Author -> Creator - * - * Field: dc:creator - * - * Type: seq ProperName - * - * Category: External - * - * Description: The authors of the resource (listed in order of - * precedence, if significant). - * - * Bibtex-Fields used: author - */ - if (FieldName.AUTHOR.equals(field.getKey())) { - String authors = field.getValue(); - AuthorList list = AuthorList.parse(authors); - - for (Author author : list.getAuthors()) { - dcSchema.addCreator(author.getFirstLast(false)); - } - continue; - } - - if (FieldName.MONTH.equals(field.getKey())) { - // Dealt with in year - continue; - } - - if (FieldName.YEAR.equals(field.getKey())) { - - /* - * Year + Month -> Date - * - * Field: dc:date - * - * Type: seq Date - * - * Category: External - * - * Description: Date(s) that something interesting happened to - * the resource. - * - * Bibtex-Fields used: year, month - */ - entry.getFieldOrAlias(FieldName.DATE) - .ifPresent(publicationDate -> dcSchema.addSequenceValue("dc:date", publicationDate)); - continue; - } - - /* - * Abstract -> Description - * - * Field: dc:description - * - * Type: Lang Alt - * - * Category: External - * - * Description: A textual description of the content of the - * resource. Multiple values may be present for different languages. - * - * Bibtex-Fields used: abstract - */ - if (FieldName.ABSTRACT.equals(field.getKey())) { - dcSchema.setDescription(field.getValue()); - continue; - } - - /* - * DOI -> identifier - * - * Field: dc:identifier - * - * Type: Text - * - * Category: External - * - * Description: Unique identifier of the resource. - * - * Bibtex-Fields used: doi - */ - if (FieldName.DOI.equals(field.getKey())) { - dcSchema.setIdentifier(field.getValue()); - continue; - } - - /* - * ? -> Language - * - * Unmapped - * - * dc:language bag Locale Internal An unordered array specifying the - * languages used in the resource. - */ - - /* - * Publisher -> Publisher - * - * Field: dc:publisher - * - * Type: bag ProperName - * - * Category: External - * - * Description: Publishers. - * - * Bibtex-Fields used: doi - */ - if (FieldName.PUBLISHER.equals(field.getKey())) { - dcSchema.addPublisher(field.getValue()); - continue; - } - - /* - * ? -> Rights - * - * Unmapped - * - * dc:rights Lang Alt External Informal rights statement, selected - * by language. - */ - - /* - * ? -> Source - * - * Unmapped - * - * dc:source Text External Unique identifier of the work from which - * this resource was derived. - */ - - /* - * Keywords -> Subject - * - * Field: dc:subject - * - * Type: bag Text - * - * Category: External - * - * Description: An unordered array of descriptive phrases or - * keywords that specify the topic of the content of the resource. - * - * Bibtex-Fields used: doi - */ - if (FieldName.KEYWORDS.equals(field.getKey())) { - String o = field.getValue(); - String[] keywords = o.split(","); - for (String keyword : keywords) { - dcSchema.addSubject(keyword.trim()); - } - continue; - } - - /* - * Title -> Title - * - * Field: dc:title - * - * Type: Lang Alt - * - * Category: External - * - * Description: The title of the document, or the name given to the - * resource. Typically, it will be a name by which the resource is - * formally known. - * - * Bibtex-Fields used: title - */ - if (FieldName.TITLE.equals(field.getKey())) { - dcSchema.setTitle(field.getValue()); - continue; - } - - /* - * All others (including the bibtex key) get packaged in the - * relation attribute - */ - String o = field.getValue(); - dcSchema.addRelation("bibtex/" + field.getKey() + '/' + o); - } - - /* - * ? -> Format - * - * Unmapped - * - * dc:format MIMEType Internal The file format used when saving the - * resource. Tools and applications should set this property to the save - * format of the data. It may include appropriate qualifiers. - */ - dcSchema.setFormat("application/pdf"); - - /* - * entrytype -> Type - * - * Field: dc:type - * - * Type: bag open Choice - * - * Category: External - * - * Description: A document type; for example, novel, poem, or working - * paper. - * - * Bibtex-Fields used: entrytype - */ - TypedBibEntry typedEntry = new TypedBibEntry(entry, BibDatabaseMode.BIBTEX); - String o = typedEntry.getTypeForDisplay(); - if (!o.isEmpty()) { - dcSchema.addType(o); - } - } - - /** - * Try to write the given BibTexEntry as a DublinCore XMP Schema - * - * Existing DublinCore schemas in the document are not modified. - * - * @param document The pdf document to write to. - * @param entry The BibTeX entry that is written as a schema. - * @param database maybenull An optional database which the given BibTeX entries belong to, which will be used to - * resolve strings. If the database is null the strings will not be resolved. - */ - public static void writeDublinCore(PDDocument document, BibEntry entry, - BibDatabase database, XMPPreferences xmpPreferences) throws IOException, TransformerException { - - List entries = new ArrayList<>(); - entries.add(entry); - - XMPUtil.writeDublinCore(document, entries, database, xmpPreferences); - } - - /** - * Try to write the given BibTexEntries as DublinCore XMP Schemas - * - * Existing DublinCore schemas in the document are removed - * - * @param document The pdf document to write to. - * @param entries The BibTeX entries that are written as schemas - * @param database maybenull An optional database which the given BibTeX entries belong to, which will be used to - * resolve strings. If the database is null the strings will not be resolved. - */ - private static void writeDublinCore(PDDocument document, - Collection entries, BibDatabase database, XMPPreferences xmpPreferences) - throws IOException, TransformerException { - - Collection resolvedEntries; - if (database == null) { - resolvedEntries = entries; - } else { - resolvedEntries = database.resolveForStrings(entries, false); - } - - PDDocumentCatalog catalog = document.getDocumentCatalog(); - PDMetadata metaRaw = catalog.getMetadata(); - - XMPMetadata meta; - if (metaRaw == null) { - meta = new XMPMetadata(); - } else { - meta = new XMPMetadata(XMLUtil.parse(metaRaw.createInputStream())); - } - - // Remove all current Dublin-Core schemas - List schemas = meta - .getSchemasByNamespaceURI(XMPSchemaDublinCore.NAMESPACE); - for (XMPSchema schema : schemas) { - schema.getElement().getParentNode().removeChild(schema.getElement()); - } - - for (BibEntry entry : resolvedEntries) { - XMPSchemaDublinCore dcSchema = new XMPSchemaDublinCore(meta); - XMPUtil.writeToDCSchema(dcSchema, entry, null, xmpPreferences); - meta.addSchema(dcSchema); - } - - // Save to stream and then input that stream to the PDF - ByteArrayOutputStream os = new ByteArrayOutputStream(); - meta.save(os); - ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray()); - PDMetadata metadataStream = new PDMetadata(document, is, false); - catalog.setMetadata(metadataStream); - } - - /** - * Try to write the given BibTexEntry in the Document Information (the - * properties of the pdf). - * - * Existing fields values are overriden if the bibtex entry has the - * corresponding value set. - * - * @param document The pdf document to write to. - * @param entry The Bibtex entry that is written into the PDF properties. * - * @param database maybenull An optional database which the given bibtex entries belong to, which will be used to - * resolve strings. If the database is null the strings will not be resolved. - */ - private static void writeDocumentInformation(PDDocument document, - BibEntry entry, BibDatabase database, XMPPreferences xmpPreferences) { - - PDDocumentInformation di = document.getDocumentInformation(); - - BibEntry resolvedEntry; - if (database == null) { - resolvedEntry = entry; - } else { - resolvedEntry = database.resolveForStrings(entry, false); - } - - // Query privacy filter settings - boolean useXmpPrivacyFilter = xmpPreferences.isUseXMPPrivacyFilter(); - // Fields for which not to write XMP data later on: - Set filters = new TreeSet<>(xmpPreferences.getXmpPrivacyFilter()); - - // Set all the values including key and entryType - for (Entry field : resolvedEntry.getFieldMap().entrySet()) { - - String fieldName = field.getKey(); - String fieldContent = field.getValue(); - - if (useXmpPrivacyFilter && filters.contains(fieldName)) { - // erase field instead of adding it - if (FieldName.AUTHOR.equals(fieldName)) { - di.setAuthor(null); - } else if (FieldName.TITLE.equals(fieldName)) { - di.setTitle(null); - } else if (FieldName.KEYWORDS.equals(fieldName)) { - di.setKeywords(null); - } else if (FieldName.ABSTRACT.equals(fieldName)) { - di.setSubject(null); - } else { - di.setCustomMetadataValue("bibtex/" + fieldName, null); - } - continue; - } - - if (FieldName.AUTHOR.equals(fieldName)) { - di.setAuthor(fieldContent); - } else if (FieldName.TITLE.equals(fieldName)) { - di.setTitle(fieldContent); - } else if (FieldName.KEYWORDS.equals(fieldName)) { - di.setKeywords(fieldContent); - } else if (FieldName.ABSTRACT.equals(fieldName)) { - di.setSubject(fieldContent); - } else { - di.setCustomMetadataValue("bibtex/" + fieldName, fieldContent); - } - } - di.setCustomMetadataValue("bibtex/entrytype", StringUtil.capitalizeFirst(resolvedEntry.getType())); - } - - /** - * Try to write the given BibTexEntry in the XMP-stream of the given - * PDF-file. - * - * Throws an IOException if the file cannot be read or written, so the user - * can remove a lock or cancel the operation. - * - * The method will overwrite existing BibTeX-XMP-data, but keep other - * existing metadata. - * - * @param file The file to write the entries to. - * @param bibtexEntries The entries to write to the file. * - * @param database maybenull An optional database which the given bibtex entries belong to, which will be used - * to resolve strings. If the database is null the strings will not be resolved. - * @param writePDFInfo Write information also in PDF document properties - * @throws TransformerException If the entry was malformed or unsupported. - * @throws IOException If the file could not be written to or could not be found. - */ - public static void writeXMP(File file, - Collection bibtexEntries, BibDatabase database, - boolean writePDFInfo, XMPPreferences xmpPreferences) throws IOException, TransformerException { - - Collection resolvedEntries; - if (database == null) { - resolvedEntries = bibtexEntries; - } else { - resolvedEntries = database.resolveForStrings(bibtexEntries, false); - } - - try (PDDocument document = PDDocument.load(file.getAbsoluteFile())) { - if (document.isEncrypted()) { - throw new EncryptedPdfsNotSupportedException(); - } - - if (writePDFInfo && (resolvedEntries.size() == 1)) { - XMPUtil.writeDocumentInformation(document, resolvedEntries - .iterator().next(), null, xmpPreferences); - XMPUtil.writeDublinCore(document, resolvedEntries, null, xmpPreferences); - } - - PDDocumentCatalog catalog = document.getDocumentCatalog(); - PDMetadata metaRaw = catalog.getMetadata(); - - XMPMetadata meta; - if (metaRaw == null) { - meta = new XMPMetadata(); - } else { - meta = new XMPMetadata(XMLUtil.parse(metaRaw.createInputStream())); - } - meta.addXMLNSMapping(XMPSchemaBibtex.NAMESPACE, - XMPSchemaBibtex.class); - - // Remove all current Bibtex-schemas - List schemas = meta - .getSchemasByNamespaceURI(XMPSchemaBibtex.NAMESPACE); - for (XMPSchema schema : schemas) { - XMPSchemaBibtex bib = (XMPSchemaBibtex) schema; - bib.getElement().getParentNode().removeChild(bib.getElement()); - } - - for (BibEntry e : resolvedEntries) { - XMPSchemaBibtex bibtex = new XMPSchemaBibtex(meta); - meta.addSchema(bibtex); - bibtex.setBibtexEntry(e, xmpPreferences); - } - - // Save to stream and then input that stream to the PDF - ByteArrayOutputStream os = new ByteArrayOutputStream(); - meta.save(os); - ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray()); - PDMetadata metadataStream = new PDMetadata(document, is, false); - catalog.setMetadata(metadataStream); - - // Save - try { - document.save(file.getAbsolutePath()); - } catch (COSVisitorException e) { - LOGGER.debug("Could not write XMP metadata", e); - throw new TransformerException("Could not write XMP metadata: " + e.getLocalizedMessage(), e); - } - } - } - - /** - * see XMPUtil.hasMetadata(InputStream) - */ - public static boolean hasMetadata(Path path, XMPPreferences xmpPreferences) { - try (InputStream inputStream = Files.newInputStream(path, StandardOpenOption.READ)) { - return hasMetadata(inputStream, xmpPreferences); - } catch (IOException e) { - // happens if no metadata is found, no reason to log the exception - return false; - } - } - - /** - * Will try to read XMP metadata from the given file, returning whether - * metadata was found. - * - * Caution: This method is as expensive as it is reading the actual metadata - * itself from the PDF. - * - * @param inputStream The inputStream to read the PDF from. - * @return whether a BibEntry was found in the given PDF. - */ - public static boolean hasMetadata(InputStream inputStream, XMPPreferences xmpPreferences) { - try { - List bibEntries = XMPUtil.readXMP(inputStream, xmpPreferences); - return !bibEntries.isEmpty(); - } catch (EncryptedPdfsNotSupportedException ex) { - LOGGER.info("Encryption not supported by XMPUtil"); - return false; - } catch (IOException e) { - // happens if no metadata is found, no reason to log the exception - return false; - } - } -} diff --git a/src/main/java/org/jabref/logic/xmp/XMPPreferences.java b/src/main/java/org/jabref/logic/xmp/XmpPreferences.java similarity index 87% rename from src/main/java/org/jabref/logic/xmp/XMPPreferences.java rename to src/main/java/org/jabref/logic/xmp/XmpPreferences.java index 63470719a5c..688082be464 100644 --- a/src/main/java/org/jabref/logic/xmp/XMPPreferences.java +++ b/src/main/java/org/jabref/logic/xmp/XmpPreferences.java @@ -2,14 +2,14 @@ import java.util.List; -public class XMPPreferences { +public class XmpPreferences { private final boolean useXMPPrivacyFilter; private final List xmpPrivacyFilter; private final Character keywordSeparator; - public XMPPreferences(boolean useXMPPrivacyFilter, List xmpPrivacyFilter, Character keywordSeparator) { + public XmpPreferences(boolean useXMPPrivacyFilter, List xmpPrivacyFilter, Character keywordSeparator) { this.useXMPPrivacyFilter = useXMPPrivacyFilter; this.xmpPrivacyFilter = xmpPrivacyFilter; this.keywordSeparator = keywordSeparator; diff --git a/src/main/java/org/jabref/logic/xmp/XmpUtilReader.java b/src/main/java/org/jabref/logic/xmp/XmpUtilReader.java new file mode 100644 index 00000000000..29d17ba9f88 --- /dev/null +++ b/src/main/java/org/jabref/logic/xmp/XmpUtilReader.java @@ -0,0 +1,155 @@ +package org.jabref.logic.xmp; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Optional; + +import org.jabref.model.entry.BibEntry; + +import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.pdmodel.PDDocumentCatalog; +import org.apache.pdfbox.pdmodel.PDDocumentInformation; +import org.apache.pdfbox.pdmodel.common.PDMetadata; +import org.apache.xmpbox.XMPMetadata; +import org.apache.xmpbox.schema.DublinCoreSchema; + +public class XmpUtilReader { + + private static final String START_TAG = " readRawXmp(Path path) throws IOException { + try (PDDocument document = XmpUtilReader.loadWithAutomaticDecryption(path)) { + return XmpUtilReader.getXmpMetadata(document); + } + } + + /** + * Convenience method for readXMP(File). + * + * @param filename The filename from which to open the file. + * @return BibtexEntryies found in the PDF or an empty list + */ + public static List readXmp(String filename, XmpPreferences xmpPreferences) throws IOException { + return XmpUtilReader.readXmp(Paths.get(filename), xmpPreferences); + } + + /** + * Try to read the given BibTexEntry from the XMP-stream of the given + * inputstream containing a PDF-file. + * + * Only supports Dublin Core as a metadata format. + * + * @param path The path to read from. + * @return list of BibEntries retrieved from the stream. May be empty, but never null + * @throws IOException Throws an IOException if the file cannot be read, so the user than remove a lock or cancel + * the operation. + */ + public static List readXmp(Path path, XmpPreferences xmpPreferences) + throws IOException { + + List result = new LinkedList<>(); + + try (PDDocument document = loadWithAutomaticDecryption(path)) { + List xmpMetaList = XmpUtilReader.getXmpMetadata(document); + + if (!xmpMetaList.isEmpty()) { + // Only support Dublin Core since JabRef 4.2 + for (XMPMetadata xmpMeta : xmpMetaList) { + DublinCoreSchema dcSchema = xmpMeta.getDublinCoreSchema(); + + if (dcSchema != null) { + DublinCoreExtractor dcExtractor = new DublinCoreExtractor(dcSchema, xmpPreferences, new BibEntry()); + Optional entry = dcExtractor.extractBibtexEntry(); + + if (entry.isPresent()) { + result.add(entry.get()); + } + } + } + } + if (result.isEmpty()) { + // If we did not find any XMP metadata, search for non XMP metadata + PDDocumentInformation documentInformation = document.getDocumentInformation(); + DocumentInformationExtractor diExtractor = new DocumentInformationExtractor(documentInformation); + Optional entry = diExtractor.extractBibtexEntry(); + entry.ifPresent(result::add); + } + } + + // return empty list, if no metadata was found + if (result.isEmpty()) { + return Collections.emptyList(); + } + return result; + } + + /** + * This method is a hack to generate multiple XMPMetadata objects, because the + * implementation of the pdfbox does not support methods for reading multiple + * DublinCoreSchemas from a single metadata entry. + *

+ * + * + * @return empty Optional if no metadata has been found + */ + private static List getXmpMetadata(PDDocument document) throws IOException { + PDDocumentCatalog catalog = document.getDocumentCatalog(); + PDMetadata metaRaw = catalog.getMetadata(); + List metaList = new ArrayList<>(); + + if (metaRaw == null) { + return metaList; + } + + String xmp = metaRaw.getCOSObject().toTextString(); + + int startDescriptionSection = xmp.indexOf(START_TAG); + int endDescriptionSection = xmp.lastIndexOf(END_TAG) + END_TAG.length(); + + // XML header for the xmpDomParser + String start = xmp.substring(0, startDescriptionSection); + // descriptionArray - mid part of the textual metadata + String[] descriptionsArray = xmp.substring(startDescriptionSection, endDescriptionSection).split(END_TAG); + // XML footer for the xmpDomParser + String end = xmp.substring(endDescriptionSection); + + for (String s : descriptionsArray) { + // END_TAG is appended, because of the split operation above + String xmpMetaString = start + s + END_TAG + end; + metaList.add(XmpUtilShared.parseXmpMetadata(new ByteArrayInputStream(xmpMetaString.getBytes()))); + } + return metaList; + } + + /** + * Loads the specified file with the basic pdfbox functionality and uses an empty string as default password. + * + * @param path The path to load. + * @return + * @throws IOException from the underlying {@link PDDocument#load(File)} + */ + public static PDDocument loadWithAutomaticDecryption(Path path) throws IOException { + // try to load the document + // also uses an empty string as default password + PDDocument doc = PDDocument.load(path.toFile()); + return doc; + } +} diff --git a/src/main/java/org/jabref/logic/xmp/XmpUtilShared.java b/src/main/java/org/jabref/logic/xmp/XmpUtilShared.java new file mode 100644 index 00000000000..4dc65b77a68 --- /dev/null +++ b/src/main/java/org/jabref/logic/xmp/XmpUtilShared.java @@ -0,0 +1,60 @@ +package org.jabref.logic.xmp; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Path; +import java.util.List; + +import org.jabref.model.entry.BibEntry; + +import org.apache.xmpbox.XMPMetadata; +import org.apache.xmpbox.xml.DomXmpParser; +import org.apache.xmpbox.xml.XmpParsingException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * XMPUtilShared provides support for reading (@link XMPUtilReader) and writing (@link XMPUtilWriter) BibTex data as XMP-Metadata + * in PDF-documents. + */ +public class XmpUtilShared { + + private static final Logger LOGGER = LoggerFactory.getLogger(XmpUtilShared.class); + + private XmpUtilShared() { + } + + protected static XMPMetadata parseXmpMetadata(InputStream is) throws IOException { + XMPMetadata meta = null; + try { + DomXmpParser parser = new DomXmpParser(); + meta = parser.parse(is); + return meta; + } catch (XmpParsingException e) { + throw new IOException(e); + } + } + + /** + * Will try to read XMP metadata from the given file, returning whether + * metadata was found. + * + * Caution: This method is as expensive as it is reading the actual metadata + * itself from the PDF. + * + * @param inputStream The inputStream to read the PDF from. + * @return whether a BibEntry was found in the given PDF. + */ + public static boolean hasMetadata(Path path, XmpPreferences xmpPreferences) { + try { + List bibEntries = XmpUtilReader.readXmp(path, xmpPreferences); + return !bibEntries.isEmpty(); + } catch (EncryptedPdfsNotSupportedException ex) { + LOGGER.info("Encryption not supported by XMPUtil"); + return false; + } catch (IOException e) { + XmpUtilShared.LOGGER.debug("No metadata was found. Path: " + path.toString()); + return false; + } + } +} diff --git a/src/main/java/org/jabref/logic/xmp/XmpUtilWriter.java b/src/main/java/org/jabref/logic/xmp/XmpUtilWriter.java new file mode 100644 index 00000000000..45f10167009 --- /dev/null +++ b/src/main/java/org/jabref/logic/xmp/XmpUtilWriter.java @@ -0,0 +1,281 @@ +package org.jabref.logic.xmp; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; +import java.util.Map.Entry; +import java.util.Set; +import java.util.TreeSet; + +import javax.xml.transform.TransformerException; + +import org.jabref.model.database.BibDatabase; +import org.jabref.model.entry.BibEntry; +import org.jabref.model.entry.FieldName; +import org.jabref.model.strings.StringUtil; + +import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.pdmodel.PDDocumentCatalog; +import org.apache.pdfbox.pdmodel.PDDocumentInformation; +import org.apache.pdfbox.pdmodel.common.PDMetadata; +import org.apache.xmpbox.XMPMetadata; +import org.apache.xmpbox.schema.DublinCoreSchema; +import org.apache.xmpbox.xml.XmpSerializer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class XmpUtilWriter { + + private static final Logger LOGGER = LoggerFactory.getLogger(XmpUtilWriter.class); + + /** + * Try to write the given BibTexEntry in the XMP-stream of the given + * PDF-file. + * + * Throws an IOException if the file cannot be read or written, so the user + * can remove a lock or cancel the operation. + * + * The method will overwrite existing BibTeX-XMP-data, but keep other + * existing metadata. + * + * This is a convenience method for writeXMP(File, BibEntry). + * + * @param filename The filename from which to open the file. + * @param entry The entry to write. + * @param database maybenull An optional database which the given bibtex entries belong to, which will be used to + * resolve strings. If the database is null the strings will not be resolved. + * @throws TransformerException If the entry was malformed or unsupported. + * @throws IOException If the file could not be written to or could not be found. + */ + public static void writeXmp(String fileName, BibEntry entry, + BibDatabase database, XmpPreferences xmpPreferences) throws IOException, TransformerException { + XmpUtilWriter.writeXmp(Paths.get(fileName), entry, database, xmpPreferences); + } + + /** + * Try to write the given BibTexEntry in the XMP-stream of the given + * PDF-file. + * + * Throws an IOException if the file cannot be read or written, so the user + * can remove a lock or cancel the operation. + * + * The method will overwrite existing BibTeX-XMP-data, but keep other + * existing metadata. + * + * This is a convenience method for writeXMP(File, Collection). + * + * @param path The path to write to. + * @param entry The entry to write. + * @param database maybenull An optional database which the given bibtex entries belong to, which will be used to + * resolve strings. If the database is null the strings will not be resolved. + * @throws TransformerException If the entry was malformed or unsupported. + * @throws IOException If the file could not be written to or could not be found. + */ + public static void writeXmp(Path file, BibEntry entry, + BibDatabase database, XmpPreferences xmpPreferences) throws IOException, TransformerException { + List bibEntryList = new ArrayList<>(); + bibEntryList.add(entry); + XmpUtilWriter.writeXmp(file, bibEntryList, database, xmpPreferences); + } + + private static void writeToDCSchema(DublinCoreSchema dcSchema, BibEntry entry, BibDatabase database, + XmpPreferences xmpPreferences) { + + BibEntry resolvedEntry = XmpUtilWriter.getDefaultOrDatabaseEntry(entry, database); + + DublinCoreExtractor dcExtractor = new DublinCoreExtractor(dcSchema, xmpPreferences, resolvedEntry); + dcExtractor.fillDublinCoreSchema(); + } + + + /** + * Try to write the given BibTexEntry as a DublinCore XMP Schema + * + * Existing DublinCore schemas in the document are not modified. + * + * @param document The pdf document to write to. + * @param entry The BibTeX entry that is written as a schema. + * @param database maybenull An optional database which the given BibTeX entries belong to, which will be used to + * resolve strings. If the database is null the strings will not be resolved. + */ + public static void writeDublinCore(PDDocument document, BibEntry entry, + BibDatabase database, XmpPreferences xmpPreferences) throws IOException, TransformerException { + + List entries = new ArrayList<>(); + entries.add(entry); + + XmpUtilWriter.writeDublinCore(document, entries, database, xmpPreferences); + } + + /** + * Try to write the given BibTexEntries as DublinCore XMP Schemas + * + * Existing DublinCore schemas in the document are removed + * + * @param document The pdf document to write to. + * @param entries The BibTeX entries that are written as schemas + * @param database maybenull An optional database which the given BibTeX entries belong to, which will be used to + * resolve strings. If the database is null the strings will not be resolved. + */ + private static void writeDublinCore(PDDocument document, + List entries, BibDatabase database, XmpPreferences xmpPreferences) + throws IOException, TransformerException { + + List resolvedEntries; + if (database == null) { + resolvedEntries = entries; + } else { + resolvedEntries = database.resolveForStrings(entries, false); + } + + PDDocumentCatalog catalog = document.getDocumentCatalog(); + PDMetadata metaRaw = catalog.getMetadata(); + + XMPMetadata meta; + if (metaRaw == null) { + meta = XMPMetadata.createXMPMetadata(); + } else { + meta = XmpUtilShared.parseXmpMetadata(metaRaw.createInputStream()); + } + + // Remove all current Dublin-Core schemas + meta.removeSchema(meta.getDublinCoreSchema()); + + for (BibEntry entry : resolvedEntries) { + DublinCoreSchema dcSchema = meta.createAndAddDublinCoreSchema(); + XmpUtilWriter.writeToDCSchema(dcSchema, entry, null, xmpPreferences); + } + + // Save to stream and then input that stream to the PDF + ByteArrayOutputStream os = new ByteArrayOutputStream(); + XmpSerializer serializer = new XmpSerializer(); + serializer.serialize(meta, os, true); + ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray()); + PDMetadata metadataStream = new PDMetadata(document, is); + catalog.setMetadata(metadataStream); + } + + /** + * Try to write the given BibTexEntry in the Document Information (the + * properties of the pdf). + * + * Existing fields values are overriden if the bibtex entry has the + * corresponding value set. + * + * @param document The pdf document to write to. + * @param entry The Bibtex entry that is written into the PDF properties. * + * @param database maybenull An optional database which the given bibtex entries belong to, which will be used to + * resolve strings. If the database is null the strings will not be resolved. + */ + private static void writeDocumentInformation(PDDocument document, + BibEntry entry, BibDatabase database, XmpPreferences xmpPreferences) { + + PDDocumentInformation di = document.getDocumentInformation(); + + BibEntry resolvedEntry = XmpUtilWriter.getDefaultOrDatabaseEntry(entry, database); + + // Query privacy filter settings + boolean useXmpPrivacyFilter = xmpPreferences.isUseXMPPrivacyFilter(); + // Fields for which not to write XMP data later on: + Set filters = new TreeSet<>(xmpPreferences.getXmpPrivacyFilter()); + + // Set all the values including key and entryType + for (Entry field : resolvedEntry.getFieldMap().entrySet()) { + + String fieldName = field.getKey(); + String fieldContent = field.getValue(); + + if (useXmpPrivacyFilter && filters.contains(fieldName)) { + // erase field instead of adding it + if (FieldName.AUTHOR.equals(fieldName)) { + di.setAuthor(null); + } else if (FieldName.TITLE.equals(fieldName)) { + di.setTitle(null); + } else if (FieldName.KEYWORDS.equals(fieldName)) { + di.setKeywords(null); + } else if (FieldName.ABSTRACT.equals(fieldName)) { + di.setSubject(null); + } else { + di.setCustomMetadataValue("bibtex/" + fieldName, null); + } + continue; + } + + if (FieldName.AUTHOR.equals(fieldName)) { + di.setAuthor(fieldContent); + } else if (FieldName.TITLE.equals(fieldName)) { + di.setTitle(fieldContent); + } else if (FieldName.KEYWORDS.equals(fieldName)) { + di.setKeywords(fieldContent); + } else if (FieldName.ABSTRACT.equals(fieldName)) { + di.setSubject(fieldContent); + } else { + di.setCustomMetadataValue("bibtex/" + fieldName, fieldContent); + } + } + di.setCustomMetadataValue("bibtex/entrytype", StringUtil.capitalizeFirst(resolvedEntry.getType())); + } + + /** + * Try to write the given BibTexEntry in the XMP-stream of the given + * PDF-file. + * + * Throws an IOException if the file cannot be read or written, so the user + * can remove a lock or cancel the operation. + * + * The method will overwrite existing BibTeX-XMP-data, but keep other + * existing metadata. + * + * @param file The file to write the entries to. + * @param bibtexEntries The entries to write to the file. * + * @param database maybenull An optional database which the given bibtex entries belong to, which will be used + * to resolve strings. If the database is null the strings will not be resolved. + * @param writePDFInfo Write information also in PDF document properties + * @throws TransformerException If the entry was malformed or unsupported. + * @throws IOException If the file could not be written to or could not be found. + */ + public static void writeXmp(Path path, + List bibtexEntries, BibDatabase database, + XmpPreferences xmpPreferences) throws IOException, TransformerException { + + List resolvedEntries; + if (database == null) { + resolvedEntries = bibtexEntries; + } else { + resolvedEntries = database.resolveForStrings(bibtexEntries, false); + } + + try (PDDocument document = PDDocument.load(path.toFile())) { + + if (document.isEncrypted()) { + throw new EncryptedPdfsNotSupportedException(); + } + + // Write schemas (PDDocumentInformation and DublinCoreSchema) to the document metadata + if (resolvedEntries.size() > 0) { + XmpUtilWriter.writeDocumentInformation(document, resolvedEntries.get(0), null, xmpPreferences); + XmpUtilWriter.writeDublinCore(document, resolvedEntries, null, xmpPreferences); + } + + // Save + try { + document.save(path.toFile()); + } catch (IOException e) { + LOGGER.debug("Could not write XMP metadata", e); + throw new TransformerException("Could not write XMP metadata: " + e.getLocalizedMessage(), e); + } + } + } + + private static BibEntry getDefaultOrDatabaseEntry(BibEntry defaultEntry, BibDatabase database) { + if (database == null) { + return defaultEntry; + } else { + return database.resolveForStrings(defaultEntry, false); + } + } +} diff --git a/src/main/java/org/jabref/model/pdf/FileAnnotation.java b/src/main/java/org/jabref/model/pdf/FileAnnotation.java index 53aa55c0b8e..f31955b1acc 100644 --- a/src/main/java/org/jabref/model/pdf/FileAnnotation.java +++ b/src/main/java/org/jabref/model/pdf/FileAnnotation.java @@ -52,7 +52,7 @@ public FileAnnotation(final String author, final LocalDateTime timeModified, fin * @param pageNumber The page of the pdf where the annotation occurs */ public FileAnnotation(final PDAnnotation annotation, final int pageNumber) { - this(annotation.getDictionary().getString(COSName.T), + this(annotation.getCOSObject().getString(COSName.T), extractModifiedTime(annotation.getModifiedDate()), pageNumber, annotation.getContents(), FileAnnotationType.parse(annotation), Optional.empty()); } @@ -66,7 +66,7 @@ public FileAnnotation(final PDAnnotation annotation, final int pageNumber) { * @param linkedFileAnnotation The corresponding note of a marked text area. */ public FileAnnotation(final PDAnnotation annotation, final int pageNumber, FileAnnotation linkedFileAnnotation) { - this(annotation.getDictionary().getString(COSName.T), extractModifiedTime(annotation.getModifiedDate()), + this(annotation.getCOSObject().getString(COSName.T), extractModifiedTime(annotation.getModifiedDate()), pageNumber, annotation.getContents(), FileAnnotationType.parse(annotation), Optional.of(linkedFileAnnotation)); } diff --git a/src/main/java/org/jabref/pdfimport/ImportDialog.java b/src/main/java/org/jabref/pdfimport/ImportDialog.java index f47db08fee4..c78d2ff0f3b 100644 --- a/src/main/java/org/jabref/pdfimport/ImportDialog.java +++ b/src/main/java/org/jabref/pdfimport/ImportDialog.java @@ -29,7 +29,7 @@ import org.jabref.Globals; import org.jabref.gui.JabRefDialog; import org.jabref.logic.l10n.Localization; -import org.jabref.logic.xmp.XMPUtil; +import org.jabref.logic.xmp.XmpUtilReader; import org.jabref.model.entry.BibEntry; import org.jabref.model.strings.StringUtil; import org.jabref.preferences.JabRefPreferences; @@ -180,7 +180,7 @@ public void windowClosing(WindowEvent e) { private List getEntriesFromXMP(String fileName) { List foundEntries = new ArrayList<>(); try { - foundEntries = XMPUtil.readXMP(fileName, Globals.prefs.getXMPPreferences()); + foundEntries = XmpUtilReader.readXmp(fileName, Globals.prefs.getXMPPreferences()); } catch (IOException e) { e.printStackTrace(); } diff --git a/src/main/java/org/jabref/pdfimport/PdfImporter.java b/src/main/java/org/jabref/pdfimport/PdfImporter.java index 19804ab13ca..618ed859fc7 100644 --- a/src/main/java/org/jabref/pdfimport/PdfImporter.java +++ b/src/main/java/org/jabref/pdfimport/PdfImporter.java @@ -29,7 +29,7 @@ import org.jabref.logic.l10n.Localization; import org.jabref.logic.util.UpdateField; import org.jabref.logic.util.io.FileUtil; -import org.jabref.logic.xmp.XMPUtil; +import org.jabref.logic.xmp.XmpUtilShared; import org.jabref.model.database.KeyCollisionException; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.EntryType; @@ -108,7 +108,7 @@ private List importPdfFilesInternal(List fileNames) { for (String fileName : fileNames) { if (!neverShow && !doNotShowAgain) { importDialog = new ImportDialog(dropRow >= 0, fileName); - if (!XMPUtil.hasMetadata(Paths.get(fileName), Globals.prefs.getXMPPreferences())) { + if (!XmpUtilShared.hasMetadata(Paths.get(fileName), Globals.prefs.getXMPPreferences())) { importDialog.disableXMPChoice(); } importDialog.setLocationRelativeTo(frame); @@ -155,7 +155,6 @@ private void doXMPImport(String fileName, List res) { } localRes.addAll(result.getDatabase().getEntries()); - BibEntry entry; if (localRes.isEmpty()) { // import failed -> generate default entry LOGGER.info("Import failed"); @@ -163,23 +162,21 @@ private void doXMPImport(String fileName, List res) { return; } - // only one entry is imported - entry = localRes.get(0); - - // insert entry to database and link file - panel.getDatabase().insertEntry(entry); - panel.markBaseChanged(); - FileListTableModel tm = new FileListTableModel(); - Path toLink = Paths.get(fileName); - // Get a list of file directories: - List dirsS = panel.getBibDatabaseContext() - .getFileDirectoriesAsPaths(Globals.prefs.getFileDirectoryPreferences()); - - tm.addEntry(0, new FileListEntry("", FileUtil.shortenFileName(toLink, dirsS).toString(), - ExternalFileTypes.getInstance().getExternalFileTypeByName("PDF"))); - entry.setField(FieldName.FILE, tm.getStringRepresentation()); - res.add(entry); - + for (BibEntry entry : localRes) { + // insert entry to database and link file + panel.getDatabase().insertEntry(entry); + panel.markBaseChanged(); + FileListTableModel tm = new FileListTableModel(); + Path toLink = Paths.get(fileName); + // Get a list of file directories: + List dirsS = panel.getBibDatabaseContext() + .getFileDirectoriesAsPaths(Globals.prefs.getFileDirectoryPreferences()); + + tm.addEntry(0, new FileListEntry("", FileUtil.shortenFileName(toLink, dirsS).toString(), + ExternalFileTypes.getInstance().getExternalFileTypeByName("PDF"))); + entry.setField(FieldName.FILE, tm.getStringRepresentation()); + res.add(entry); + } } private Optional createNewBlankEntry(String fileName) { diff --git a/src/main/java/org/jabref/preferences/JabRefPreferences.java b/src/main/java/org/jabref/preferences/JabRefPreferences.java index 91179882f38..a76e4666141 100644 --- a/src/main/java/org/jabref/preferences/JabRefPreferences.java +++ b/src/main/java/org/jabref/preferences/JabRefPreferences.java @@ -70,7 +70,7 @@ import org.jabref.logic.util.Version; import org.jabref.logic.util.io.AutoLinkPreferences; import org.jabref.logic.util.io.FileHistory; -import org.jabref.logic.xmp.XMPPreferences; +import org.jabref.logic.xmp.XmpPreferences; import org.jabref.model.bibtexkeypattern.GlobalBibtexKeyPattern; import org.jabref.model.database.BibDatabaseMode; import org.jabref.model.entry.BibEntry; @@ -1438,8 +1438,8 @@ public LayoutFormatterPreferences getLayoutFormatterPreferences( getFileLinkPreferences(), journalAbbreviationLoader); } - public XMPPreferences getXMPPreferences() { - return new XMPPreferences(getBoolean(USE_XMP_PRIVACY_FILTER), getStringList(XMP_PRIVACY_FILTERS), + public XmpPreferences getXMPPreferences() { + return new XmpPreferences(getBoolean(USE_XMP_PRIVACY_FILTER), getStringList(XMP_PRIVACY_FILTERS), getKeywordDelimiter()); } diff --git a/src/test/java/org/jabref/logic/importer/ImportFormatReaderIntegrationTest.java b/src/test/java/org/jabref/logic/importer/ImportFormatReaderIntegrationTest.java index bb2ef4f2fff..09f4dd4ddcd 100644 --- a/src/test/java/org/jabref/logic/importer/ImportFormatReaderIntegrationTest.java +++ b/src/test/java/org/jabref/logic/importer/ImportFormatReaderIntegrationTest.java @@ -8,7 +8,7 @@ import java.util.ArrayList; import java.util.Collection; -import org.jabref.logic.xmp.XMPPreferences; +import org.jabref.logic.xmp.XmpPreferences; import org.jabref.model.util.DummyFileUpdateMonitor; import org.junit.Before; @@ -42,7 +42,7 @@ public void setUp() { reader = new ImportFormatReader(); ImportFormatPreferences importFormatPreferences = mock(ImportFormatPreferences.class, Answers.RETURNS_DEEP_STUBS); when(importFormatPreferences.getEncoding()).thenReturn(StandardCharsets.UTF_8); - reader.resetImportFormats(importFormatPreferences, mock(XMPPreferences.class), new DummyFileUpdateMonitor()); + reader.resetImportFormats(importFormatPreferences, mock(XmpPreferences.class), new DummyFileUpdateMonitor()); } @Test diff --git a/src/test/java/org/jabref/logic/importer/ImportFormatReaderTestParameterless.java b/src/test/java/org/jabref/logic/importer/ImportFormatReaderTestParameterless.java index 8214133dbcd..4a8b34dc95d 100644 --- a/src/test/java/org/jabref/logic/importer/ImportFormatReaderTestParameterless.java +++ b/src/test/java/org/jabref/logic/importer/ImportFormatReaderTestParameterless.java @@ -4,7 +4,7 @@ import java.nio.file.Path; import java.nio.file.Paths; -import org.jabref.logic.xmp.XMPPreferences; +import org.jabref.logic.xmp.XmpPreferences; import org.jabref.model.util.DummyFileUpdateMonitor; import org.jabref.model.util.FileUpdateMonitor; @@ -26,7 +26,7 @@ public void setUp() { reader = new ImportFormatReader(); ImportFormatPreferences importFormatPreferences = mock(ImportFormatPreferences.class, Answers.RETURNS_DEEP_STUBS); when(importFormatPreferences.getEncoding()).thenReturn(StandardCharsets.UTF_8); - reader.resetImportFormats(importFormatPreferences, mock(XMPPreferences.class), fileMonitor); + reader.resetImportFormats(importFormatPreferences, mock(XmpPreferences.class), fileMonitor); } @Test diff --git a/src/test/java/org/jabref/logic/importer/ImporterTest.java b/src/test/java/org/jabref/logic/importer/ImporterTest.java index e797e21ec2d..31e74e3e7db 100644 --- a/src/test/java/org/jabref/logic/importer/ImporterTest.java +++ b/src/test/java/org/jabref/logic/importer/ImporterTest.java @@ -24,7 +24,7 @@ import org.jabref.logic.importer.fileformat.RepecNepImporter; import org.jabref.logic.importer.fileformat.RisImporter; import org.jabref.logic.importer.fileformat.SilverPlatterImporter; -import org.jabref.logic.xmp.XMPPreferences; +import org.jabref.logic.xmp.XmpPreferences; import org.jabref.model.util.DummyFileUpdateMonitor; import org.junit.Assert; @@ -102,7 +102,7 @@ public static Collection instancesToTest() { // sorted alphabetically ImportFormatPreferences importFormatPreferences = mock(ImportFormatPreferences.class); - XMPPreferences xmpPreferences = mock(XMPPreferences.class); + XmpPreferences xmpPreferences = mock(XmpPreferences.class); // @formatter:off return Arrays.asList( new Object[]{new BiblioscapeImporter()}, diff --git a/src/test/java/org/jabref/logic/importer/fileformat/PdfXmpImporterTest.java b/src/test/java/org/jabref/logic/importer/fileformat/PdfXmpImporterTest.java index 6c216a072a2..c67684e122a 100644 --- a/src/test/java/org/jabref/logic/importer/fileformat/PdfXmpImporterTest.java +++ b/src/test/java/org/jabref/logic/importer/fileformat/PdfXmpImporterTest.java @@ -12,7 +12,7 @@ import org.jabref.logic.importer.ParserResult; import org.jabref.logic.util.FileType; -import org.jabref.logic.xmp.XMPPreferences; +import org.jabref.logic.xmp.XmpPreferences; import org.jabref.model.entry.BibEntry; import org.junit.jupiter.api.BeforeEach; @@ -35,7 +35,7 @@ private static Stream invalidFileNames() throws IOException { @BeforeEach public void setUp() { - importer = new PdfXmpImporter(mock(XMPPreferences.class)); + importer = new PdfXmpImporter(mock(XmpPreferences.class)); } @Test diff --git a/src/test/java/org/jabref/logic/xmp/XMPSchemaBibtexTest.java b/src/test/java/org/jabref/logic/xmp/XMPSchemaBibtexTest.java deleted file mode 100644 index 377ffebaa9e..00000000000 --- a/src/test/java/org/jabref/logic/xmp/XMPSchemaBibtexTest.java +++ /dev/null @@ -1,285 +0,0 @@ -package org.jabref.logic.xmp; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.util.List; -import java.util.Map; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; - -import org.jabref.BibtexTestData; -import org.jabref.logic.bibtex.FieldContentParserPreferences; -import org.jabref.logic.importer.ImportFormatPreferences; -import org.jabref.model.entry.BibEntry; - -import org.apache.jempbox.impl.XMLUtil; -import org.apache.jempbox.xmp.XMPMetadata; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.NodeList; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -public class XMPSchemaBibtexTest { - - private ImportFormatPreferences prefs; - - @BeforeEach - public void setUp() { - prefs = mock(ImportFormatPreferences.class); - } - - public void assertEqualsBibtexEntry(BibEntry e, BibEntry x) { - assertNotNull(e); - assertNotNull(x); - assertEquals(e.getCiteKeyOptional(), x.getCiteKeyOptional()); - assertEquals(e.getType(), x.getType()); - - assertEquals(e.getFieldNames().size(), x.getFieldNames().size()); - - for (String name : e.getFieldNames()) { - assertEquals(e.getField(name), x.getField(name)); - } - } - - @Test - public void testXMPSchemaBibtexXMPMetadata() throws IOException { - - XMPMetadata xmp = new XMPMetadata(); - XMPSchemaBibtex bibtex = new XMPSchemaBibtex(xmp); - - assertNotNull(bibtex.getElement()); - assertEquals("rdf:Description", bibtex.getElement().getTagName()); - - } - - @Test - public void testXMPSchemaBibtexElement() - throws ParserConfigurationException { - DocumentBuilderFactory builderFactory = DocumentBuilderFactory - .newInstance(); - DocumentBuilder builder = builderFactory.newDocumentBuilder(); - Element e = builder.newDocument().createElement("rdf:Description"); - - XMPSchemaBibtex bibtex = new XMPSchemaBibtex(e, "bibtex"); - - assertEquals(e, bibtex.getElement()); - assertEquals("rdf:Description", bibtex.getElement().getTagName()); - } - - @Test - public void testGetSetPersonList() throws IOException { - XMPMetadata xmp = new XMPMetadata(); - XMPSchemaBibtex bibtex = new XMPSchemaBibtex(xmp); - - bibtex.setPersonList("author", "Tom DeMarco and Kent Beck"); - - Element e = bibtex.getElement(); - - NodeList l1 = e.getElementsByTagName("bibtex:author"); - assertEquals(1, l1.getLength()); - - NodeList l = e.getElementsByTagName("rdf:li"); - - assertEquals(2, l.getLength()); - - assertEquals("Tom DeMarco", XMLUtil - .getStringValue((Element) l.item(0))); - assertEquals("Kent Beck", XMLUtil.getStringValue((Element) l.item(1))); - - List authors = bibtex.getPersonList("author"); - assertEquals(2, authors.size()); - - assertEquals("Tom DeMarco", authors.get(0)); - assertEquals("Kent Beck", authors.get(1)); - } - - @Test - public void testSetGetTextPropertyString() throws IOException { - XMPMetadata xmp = new XMPMetadata(); - XMPSchemaBibtex bibtex = new XMPSchemaBibtex(xmp); - - bibtex.setTextProperty("title", - "The advanced Flux-Compensation for Delawney-Separation"); - - Element e = bibtex.getElement(); - assertEquals("The advanced Flux-Compensation for Delawney-Separation", - e.getAttribute("bibtex:title")); - - assertEquals("The advanced Flux-Compensation for Delawney-Separation", - bibtex.getTextProperty("title")); - - bibtex.setTextProperty("title", - "The advanced Flux-Correlation for Delawney-Separation"); - - e = bibtex.getElement(); - assertEquals("The advanced Flux-Correlation for Delawney-Separation", e - .getAttribute("bibtex:title")); - - assertEquals("The advanced Flux-Correlation for Delawney-Separation", - bibtex.getTextProperty("title")); - - bibtex - .setTextProperty( - "abstract", - " The abstract\n can go \n \n on several \n lines with \n many \n\n empty ones in \n between."); - assertEquals( - " The abstract\n can go \n \n on several \n lines with \n many \n\n empty ones in \n between.", - bibtex.getTextProperty("abstract")); - } - - @Test - public void testSetGetBagListString() throws IOException { - - XMPMetadata xmp = new XMPMetadata(); - XMPSchemaBibtex bibtex = new XMPSchemaBibtex(xmp); - - bibtex.addBagValue("author", "Tom DeMarco"); - bibtex.addBagValue("author", "Kent Beck"); - { - - List l = bibtex.getBagList("author"); - - assertEquals(2, l.size()); - - assertTrue(l.get(0).equals("Tom DeMarco") - || l.get(1).equals("Tom DeMarco")); - assertTrue(l.get(0).equals("Kent Beck") - || l.get(1).equals("Kent Beck")); - } - { - bibtex.removeBagValue("author", "Kent Beck"); - List l = bibtex.getBagList("author"); - assertEquals(1, l.size()); - assertTrue(l.get(0).equals("Tom DeMarco")); - } - { // Already removed - bibtex.removeBagValue("author", "Kent Beck"); - List l = bibtex.getBagList("author"); - assertEquals(1, l.size()); - assertTrue(l.get(0).equals("Tom DeMarco")); - } - { // Duplicates allowed! - bibtex.addBagValue("author", "Tom DeMarco"); - List l = bibtex.getBagList("author"); - assertEquals(2, l.size()); - assertTrue(l.get(0).equals("Tom DeMarco")); - assertTrue(l.get(1).equals("Tom DeMarco")); - } - // Removes both - bibtex.removeBagValue("author", "Tom DeMarco"); - List l = bibtex.getBagList("author"); - assertEquals(0, l.size()); - } - - @Test - public void testGetSequenceListString() throws IOException { - - XMPMetadata xmp = new XMPMetadata(); - XMPSchemaBibtex bibtex = new XMPSchemaBibtex(xmp); - - bibtex.addSequenceValue("author", "Tom DeMarco"); - bibtex.addSequenceValue("author", "Kent Beck"); - { - - List l = bibtex.getSequenceList("author"); - - assertEquals(2, l.size()); - - assertEquals("Tom DeMarco", l.get(0)); - assertEquals("Kent Beck", l.get(1)); - } - { - bibtex.removeSequenceValue("author", "Tom DeMarco"); - List l = bibtex.getSequenceList("author"); - assertEquals(1, l.size()); - assertTrue(l.get(0).equals("Kent Beck")); - } - { // Already removed - bibtex.removeSequenceValue("author", "Tom DeMarco"); - List l = bibtex.getSequenceList("author"); - assertEquals(1, l.size()); - assertTrue(l.get(0).equals("Kent Beck")); - } - { // Duplicates allowed! - bibtex.addSequenceValue("author", "Kent Beck"); - List l = bibtex.getSequenceList("author"); - assertEquals(2, l.size()); - assertTrue(l.get(0).equals("Kent Beck")); - assertTrue(l.get(1).equals("Kent Beck")); - } - // Remvoes all - bibtex.removeSequenceValue("author", "Kent Beck"); - List l = bibtex.getSequenceList("author"); - assertEquals(0, l.size()); - } - - @Test - public void testGetAllProperties() throws IOException { - XMPMetadata xmp = new XMPMetadata(); - XMPSchemaBibtex bibtex = new XMPSchemaBibtex(xmp); - - bibtex.setTextProperty("title", "BlaBla Ta Ta\nHello World"); - bibtex.setTextProperty("abstract", "BlaBla Ta Ta\nHello World"); - bibtex.setTextProperty("review", "BlaBla Ta Ta\nHello World"); - bibtex.setTextProperty("note", "BlaBla Ta Ta\nHello World"); - bibtex.setPersonList("author", "Mouse, Mickey and Bond, James"); - - Map s = XMPSchemaBibtex.getAllProperties(bibtex, - "bibtex"); - - assertEquals(5, s.size()); - assertTrue(s.containsKey("title")); - assertTrue(s.containsKey("author")); - - assertEquals("BlaBla Ta Ta Hello World", s.get("title")); - assertEquals("BlaBla Ta Ta\nHello World", s.get("abstract")); - assertEquals("BlaBla Ta Ta\nHello World", s.get("review")); - assertEquals("BlaBla Ta Ta\nHello World", s.get("note")); - assertEquals("Mickey Mouse and James Bond", s.get("author")); - } - - @Test - public void testSetBibtexEntry() throws IOException { - when(prefs.getFieldContentParserPreferences()).thenReturn(new FieldContentParserPreferences()); - - XMPMetadata xmp = new XMPMetadata(); - XMPSchemaBibtex bibtex = new XMPSchemaBibtex(xmp); - BibEntry e = BibtexTestData.getBibtexEntry(prefs); - bibtex.setBibtexEntry(e, null); - - BibEntry e2 = bibtex.getBibtexEntry(); - - assertEqualsBibtexEntry(e, e2); - } - - @Test - public void testGetTextContent() throws IOException { - String bibtexString = "2003\n" - + "\n " - + "Beach sand convolution by surf-wave optimzation\n" - + "\n" - + "OezbekC06\n"; - - bibtexString = XMPUtilTest.bibtexXPacket(XMPUtilTest - .bibtexDescription(bibtexString)); - - Document d = XMLUtil.parse(new ByteArrayInputStream(bibtexString - .getBytes(StandardCharsets.UTF_8))); - - assertEquals("Beach sand convolution by surf-wave optimzation", - XMPSchemaBibtex.getTextContent( - d.getElementsByTagName("bibtex:title").item(0)).trim()); - - } - -} diff --git a/src/test/java/org/jabref/logic/xmp/XMPUtilTest.java b/src/test/java/org/jabref/logic/xmp/XMPUtilTest.java deleted file mode 100644 index 3d934e5741f..00000000000 --- a/src/test/java/org/jabref/logic/xmp/XMPUtilTest.java +++ /dev/null @@ -1,1397 +0,0 @@ -package org.jabref.logic.xmp; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.io.PrintStream; -import java.io.StringReader; -import java.io.StringWriter; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Calendar; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Optional; -import java.util.Set; -import java.util.TimeZone; - -import javax.xml.transform.TransformerException; - -import org.jabref.cli.XMPUtilMain; -import org.jabref.logic.bibtex.BibEntryWriter; -import org.jabref.logic.bibtex.LatexFieldFormatter; -import org.jabref.logic.bibtex.LatexFieldFormatterPreferences; -import org.jabref.logic.importer.ImportFormatPreferences; -import org.jabref.logic.importer.ParserResult; -import org.jabref.logic.importer.fileformat.BibtexParser; -import org.jabref.model.database.BibDatabaseMode; -import org.jabref.model.entry.AuthorList; -import org.jabref.model.entry.BibEntry; -import org.jabref.model.entry.BibtexEntryTypes; -import org.jabref.model.util.DummyFileUpdateMonitor; -import org.jabref.model.util.FileUpdateMonitor; - -import com.google.common.io.CharStreams; -import org.apache.jempbox.xmp.XMPMetadata; -import org.apache.jempbox.xmp.XMPSchema; -import org.apache.jempbox.xmp.XMPSchemaBasic; -import org.apache.jempbox.xmp.XMPSchemaDublinCore; -import org.apache.jempbox.xmp.XMPSchemaMediaManagement; -import org.apache.pdfbox.exceptions.COSVisitorException; -import org.apache.pdfbox.pdmodel.PDDocument; -import org.apache.pdfbox.pdmodel.PDDocumentCatalog; -import org.apache.pdfbox.pdmodel.PDPage; -import org.apache.pdfbox.pdmodel.common.PDMetadata; -import org.apache.pdfbox.util.XMLUtil; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; -import org.mockito.Answers; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -/** - * Limitations: The test suite only handles UTF8. Not UTF16. - */ -public class XMPUtilTest { - - private static final FileUpdateMonitor fileMonitor = new DummyFileUpdateMonitor(); - @Rule - public TemporaryFolder tempFolder = new TemporaryFolder(); - /** - * The PDF file that basically all operations are done upon. - */ - private File pdfFile; - - private XMPPreferences xmpPreferences; - - private ImportFormatPreferences importFormatPreferences; - - private BibtexParser parser; - - /** - * Wrap bibtex-data (...) into an rdf:Description. - * - * @param bibtex - * @return - */ - public static String bibtexDescription(String bibtex) { - return " \n" + bibtex - + "\n" + " \n"; - } - - /** - * Wrap bibtex-descriptions (rdf:Description) into the xpacket header. - * - * @param bibtexDescriptions - * @return - */ - public static String bibtexXPacket(String bibtexDescriptions) { - - StringBuilder xmp = new StringBuilder(); - - xmp.append("\n" + " \n" - + " \n") - .append(bibtexDescriptions).append(" \n" + " \n" + ""); - - return xmp.toString(); - } - - /** - * Write a manually constructed xmp-string to file - * - * @param xmpString - * @throws IOException - * @throws COSVisitorException - */ - public void writeManually(File tempFile, String xmpString) throws IOException, COSVisitorException { - - try (PDDocument document = PDDocument.load(tempFile.getAbsoluteFile())) { - if (document.isEncrypted()) { - Assert.fail("Cannot add metadata to encrypted document."); - } - - PDDocumentCatalog catalog = document.getDocumentCatalog(); - - // Convert to UTF8 and make available for metadata. - ByteArrayOutputStream bs = new ByteArrayOutputStream(); - try (OutputStreamWriter os = new OutputStreamWriter(bs, StandardCharsets.UTF_8)) { - os.write(xmpString); - } - ByteArrayInputStream in = new ByteArrayInputStream(bs.toByteArray()); - - PDMetadata metadataStream = new PDMetadata(document, in, false); - catalog.setMetadata(metadataStream); - - document.save(tempFile.getAbsolutePath()); - - } - } - - private static BibEntry bibtexString2BibtexEntry(String s, ImportFormatPreferences importFormatPreferences) - throws IOException { - ParserResult result = new BibtexParser(importFormatPreferences, fileMonitor).parse(new StringReader(s)); - Collection c = result.getDatabase().getEntries(); - Assert.assertEquals(1, c.size()); - return c.iterator().next(); - } - - private static String bibtexEntry2BibtexString(BibEntry e) throws IOException { - StringWriter sw = new StringWriter(); - new BibEntryWriter(new LatexFieldFormatter(mock(LatexFieldFormatterPreferences.class, Answers.RETURNS_DEEP_STUBS)), - false).write(e, sw, BibDatabaseMode.BIBTEX); - return sw.getBuffer().toString(); - } - - private String t1BibtexString() { - return "@article{canh05,\n" + " author = {Crowston, K. and Annabi, H. and Howison, J. and Masango, C.},\n" - + " title = {Effective work practices for floss development: A model and propositions},\n" - + " booktitle = {Hawaii International Conference On System Sciences (HICSS)},\n" + " year = {2005},\n" - + " owner = {oezbek},\n" + " timestamp = {2006.05.29},\n" - + " url = {http://james.howison.name/publications.html}}\n"; - } - - private BibEntry t1BibtexEntry() throws IOException { - return XMPUtilTest.bibtexString2BibtexEntry(t1BibtexString(), importFormatPreferences); - } - - private String t2XMP() { - return "\n" + "YeKis03 - Towards.pdf\n" + "\n"; - } - - private String t2BibtexString() throws IOException { - return XMPUtilTest.bibtexEntry2BibtexString(t2BibtexEntry()); - } - - private BibEntry t2BibtexEntry() { - BibEntry e = new BibEntry(BibtexEntryTypes.INCOLLECTION.getName()); - e.setField("title", "�pt�mz�t��n"); - e.setField("bibtexkey", "OezbekC06"); - e.setField("year", "2003"); - e.setField("booktitle", - "Proceedings of the of the 25th International Conference on Software-Engineering (Portland, Oregon)"); - e.setField("pdf", "YeKis03 - Towards.pdf"); - return e; - } - - private BibEntry t3BibtexEntry() { - BibEntry e = new BibEntry(); - e.setType(BibtexEntryTypes.INPROCEEDINGS); - e.setField("title", "Hypersonic ultra-sound"); - e.setField("bibtexkey", "Clarkson06"); - e.setField("author", "Kelly Clarkson and Ozzy Osbourne"); - e.setField("journal", "International Journal of High Fidelity"); - e.setField("booktitle", "Catch-22"); - e.setField("editor", "Huey Duck and Dewey Duck and Louie Duck"); - e.setField("pdf", "YeKis03 - Towards.pdf"); - e.setField("keywords", "peanut, butter, jelly"); - e.setField("year", "1982"); - e.setField("month", "#jul#"); - e.setField("abstract", - "The success of the Linux operating system has demonstrated the viability of an alternative form of software development—open source software—that challenges traditional assumptions about software markets. Understanding what drives open source developers to participate in open source projects is crucial for assessing the impact of open source software. This article identifies two broad types of motivations that account for their participation in open source projects. The first category includes internal factors such as intrinsic motivation and altruism, and the second category focuses on external rewards such as expected future returns and personal needs. This article also reports the results of a survey administered to open source programmers."); - return e; - } - - public String t3BibtexString() throws IOException { - return XMPUtilTest.bibtexEntry2BibtexString(t3BibtexEntry()); - } - - public String t3XMP() { - return XMPUtilTest.bibtexDescription("Hypersonic ultra-sound\n" - + "\n" + " Kelly Clarkson" - + " Ozzy Osbourne" + "" + "" - + " Huey Duck" + " Dewey Duck" + " Louie Duck" - + "" + "Clarkson06" - + "International Journal of High Fidelity" - + "Catch-22" + "YeKis03 - Towards.pdf" - + "peanut, butter, jelly" - + "Inproceedings" + "1982" - + "#jul#" - + "The success of the Linux operating system has demonstrated the viability of an alternative form of software development—open source software—that challenges traditional assumptions about software markets. Understanding what drives open source developers to participate in open source projects is crucial for assessing the impact of open source software. This article identifies two broad types of motivations that account for their participation in open source projects. The first category includes internal factors such as intrinsic motivation and altruism, and the second category focuses on external rewards such as expected future returns and personal needs. This article also reports the results of a survey administered to open source programmers."); - } - - /** - * Create a temporary PDF-file with a single empty page. - */ - @Before - public void setUp() throws IOException, COSVisitorException { - - pdfFile = tempFolder.newFile("JabRef.pdf"); - - try (PDDocument pdf = new PDDocument()) { - //Need page to open in Acrobat - pdf.addPage(new PDPage()); - pdf.save(pdfFile.getAbsolutePath()); - } - - importFormatPreferences = mock(ImportFormatPreferences.class, Answers.RETURNS_DEEP_STUBS); - when(importFormatPreferences.getEncoding()).thenReturn(StandardCharsets.UTF_8); - xmpPreferences = mock(XMPPreferences.class); - // The code assumes privacy filters to be off - when(xmpPreferences.isUseXMPPrivacyFilter()).thenReturn(false); - - when(xmpPreferences.getKeywordSeparator()).thenReturn(','); - - parser = new BibtexParser(importFormatPreferences, fileMonitor); - } - - /** - * Most basic test for reading. - * @throws IOException - * @throws COSVisitorException - */ - @Test - public void testReadXMPSimple() throws COSVisitorException, IOException { - - String bibtex = "2003\n" - + "Beach sand convolution by surf-wave optimzation\n" - + "OezbekC06\n"; - - writeManually(pdfFile, XMPUtilTest.bibtexXPacket(XMPUtilTest.bibtexDescription(bibtex))); - - List l = XMPUtil.readXMP(pdfFile.getAbsoluteFile(), xmpPreferences); - Assert.assertEquals(1, l.size()); - BibEntry e = l.get(0); - - Assert.assertNotNull(e); - Assert.assertEquals(Optional.of("OezbekC06"), e.getCiteKeyOptional()); - Assert.assertEquals(Optional.of("2003"), e.getField("year")); - Assert.assertEquals(Optional.of("Beach sand convolution by surf-wave optimzation"), - e.getField("title")); - Assert.assertEquals("misc", e.getType()); - } - - /** - * Is UTF8 handling working? This is because Java by default uses the platform encoding or a special UTF-kind. - * @throws IOException - * @throws COSVisitorException - */ - @Test - public void testReadXMPUTF8() throws COSVisitorException, IOException { - - String bibtex = "2003\n" + "�pt�mz�t��n\n" - + "OezbekC06\n"; - - writeManually(pdfFile, XMPUtilTest.bibtexXPacket(XMPUtilTest.bibtexDescription(bibtex))); - - List l = XMPUtil.readXMP(pdfFile.getAbsoluteFile(), xmpPreferences); - Assert.assertEquals(1, l.size()); - BibEntry e = l.get(0); - - Assert.assertNotNull(e); - Assert.assertEquals(Optional.of("OezbekC06"), e.getCiteKeyOptional()); - Assert.assertEquals(Optional.of("2003"), e.getField("year")); - Assert.assertEquals(Optional.of("�pt�mz�t��n"), e.getField("title")); - Assert.assertEquals("misc", e.getType()); - } - - /** - * Make sure that the privacy filter works. - * - * @throws IOException Should not happen. - * @throws TransformerException Should not happen. - */ - @Test - public void testPrivacyFilter() throws IOException, TransformerException { - when(xmpPreferences.isUseXMPPrivacyFilter()).thenReturn(true); - when(xmpPreferences.getXmpPrivacyFilter()).thenReturn(Arrays.asList("author;title;note;booktitle;year;owner;timestamp")); - - BibEntry e = t1BibtexEntry(); - - XMPUtil.writeXMP(pdfFile, e, null, xmpPreferences); - - List l = XMPUtil.readXMP(pdfFile.getAbsoluteFile(), xmpPreferences); - Assert.assertEquals(1, l.size()); - BibEntry x = l.get(0); - Set ts = x.getFieldNames(); - Assert.assertEquals(8, ts.size()); - - Assert.assertFalse(ts.contains("bibtextype")); - Assert.assertTrue(ts.contains("bibtexkey")); - Assert.assertTrue(ts.contains("year")); - Assert.assertTrue(ts.contains("url")); - } - - @Test - public void testPrivacyFilter2() throws Exception { - BibEntry e = t1BibtexEntry(); - - when(xmpPreferences.isUseXMPPrivacyFilter()).thenReturn(true); - when(xmpPreferences.getXmpPrivacyFilter()).thenReturn(Arrays.asList("author", "title", "note")); - - XMPUtil.writeXMP(pdfFile, e, null, xmpPreferences); - - List l = XMPUtil.readXMP(pdfFile.getAbsoluteFile(), xmpPreferences); - Assert.assertEquals(1, l.size()); - BibEntry x = l.get(0); - - Set expectedFields = new HashSet<>( - Arrays.asList("bibtexkey", "booktitle", "owner", "timestamp", "url", "year")); - - Assert.assertEquals(expectedFields, x.getFieldNames()); - } - - /** - * Are authors and editors correctly read? - * @throws IOException - * @throws COSVisitorException - */ - @Test - public void testReadXMPSeq() throws COSVisitorException, IOException { - - String bibtex = "\n" + " Kelly Clarkson" - + " Ozzy Osbourne" + "" + "" - + " Huey Duck" + " Dewey Duck" + " Louie Duck" - + "" + "Clarkson06"; - - writeManually(pdfFile, XMPUtilTest.bibtexXPacket(XMPUtilTest.bibtexDescription(bibtex))); - - List l = XMPUtil.readXMP(pdfFile.getAbsoluteFile(), xmpPreferences); - Assert.assertEquals(1, l.size()); - BibEntry e = l.get(0); - - Assert.assertNotNull(e); - Assert.assertEquals(Optional.of("Clarkson06"), e.getCiteKeyOptional()); - Assert.assertEquals("Kelly Clarkson and Ozzy Osbourne", e.getField("author").get()); - Assert.assertEquals("Huey Duck and Dewey Duck and Louie Duck", e.getField("editor").get()); - Assert.assertEquals("misc", e.getType()); - } - - /** - * Is the XMPEntryType correctly set? - * @throws IOException - * @throws COSVisitorException - * - */ - @Test - public void testReadXMPEntryType() throws COSVisitorException, IOException { - - String bibtex = "ARticle"; - - writeManually(pdfFile, XMPUtilTest.bibtexXPacket(XMPUtilTest.bibtexDescription(bibtex))); - - List l = XMPUtil.readXMP(pdfFile.getAbsoluteFile(), xmpPreferences); - Assert.assertEquals(1, l.size()); - BibEntry e = l.get(0); - - Assert.assertNotNull(e); - Assert.assertEquals("article", e.getType()); - } - - public static String readManually(File tempFile) throws IOException { - try (PDDocument document = PDDocument.load(tempFile.getAbsoluteFile())) { - if (document.isEncrypted()) { - Assert.fail("Cannot add metadata to encrypted document."); - } - PDDocumentCatalog catalog = document.getDocumentCatalog(); - PDMetadata meta = catalog.getMetadata(); - - if (meta == null) { - return null; - } else { - try (InputStream is = meta.createInputStream(); - InputStreamReader reader = new InputStreamReader(is, StandardCharsets.UTF_8)) { - // trim() for killing padding end-newline - return CharStreams.toString(reader).trim(); - } - } - } - } - - /** - * Test whether the helper function work correctly. - * @throws IOException - * @throws COSVisitorException - */ - @Test - public void testWriteReadManually() throws COSVisitorException, IOException { - - String bibtex = "2003\n" + "�pt�mz�t��n\n" - + "OezbekC06\n"; - - writeManually(pdfFile, XMPUtilTest.bibtexXPacket(XMPUtilTest.bibtexDescription(bibtex))); - Assert.assertEquals(XMPUtilTest.bibtexXPacket(XMPUtilTest.bibtexDescription(bibtex)), - XMPUtilTest.readManually(pdfFile)); - - bibtex = "\n" + " Kelly Clarkson" + " Ozzy Osbourne" - + "" + "" + " Huey Duck" - + " Dewey Duck" + " Louie Duck" + "" - + "Clarkson06"; - - writeManually(pdfFile, XMPUtilTest.bibtexXPacket(XMPUtilTest.bibtexDescription(bibtex))); - Assert.assertEquals(XMPUtilTest.bibtexXPacket(XMPUtilTest.bibtexDescription(bibtex)), - XMPUtilTest.readManually(pdfFile)); - } - - /** - * Test that readXMP and writeXMP work together. - * @throws IOException - * @throws TransformerException - * - */ - @Test - public void testReadWriteXMP() throws IOException, TransformerException { - ParserResult result = parser.parse(new StringReader( - "@article{canh05," + " author = {Crowston, K. and Annabi, H. and Howison, J. and Masango, C.}," + "\n" - + " title = {Effective work practices for floss development: A model and propositions}," + "\n" - + " booktitle = {Hawaii International Conference On System Sciences (HICSS)}," + "\n" - + " year = {2005}," + "\n" + " owner = {oezbek}," + "\n" + " timestamp = {2006.05.29}," - + "\n" + " url = {http://james.howison.name/publications.html}" + "\n" + "}")); - - Collection c = result.getDatabase().getEntries(); - Assert.assertEquals(1, c.size()); - - BibEntry e = c.iterator().next(); - - XMPUtil.writeXMP(pdfFile, e, null, xmpPreferences); - - List l = XMPUtil.readXMP(pdfFile.getAbsoluteFile(), xmpPreferences); - Assert.assertEquals(1, l.size()); - BibEntry x = l.get(0); - - assertEqualsBibtexEntry(e, x); - } - - /** - * Are newlines in the XML processed correctly? - * @throws IOException - * @throws COSVisitorException - * - */ - @Test - public void testNewlineHandling() throws COSVisitorException, IOException { - - String bibtex = "\nHallo\nWorld \nthis \n is\n\nnot \n\nan \n\n exercise \n \n.\n \n\n\n" - + "\nHallo\tWorld \tthis \t is\t\tnot \t\tan \t\n exercise \t \n.\t \n\t\n" - + "\n\nAbstract preserve\n\t Whitespace\n\n"; - - writeManually(pdfFile, XMPUtilTest.bibtexXPacket(XMPUtilTest.bibtexDescription(bibtex))); - - List l = XMPUtil.readXMP(pdfFile.getAbsoluteFile(), xmpPreferences); - Assert.assertEquals(1, l.size()); - BibEntry e = l.get(0); - - Assert.assertNotNull(e); - Assert.assertEquals("Hallo World this is not an exercise .", e.getField("title").get()); - Assert.assertEquals("Hallo World this is not an exercise .", e.getField("tabs").get()); - Assert.assertEquals("\n\nAbstract preserve\n\t Whitespace\n\n", e.getField("abstract").get()); - } - - /** - * Test whether XMP.readFile can deal with text-properties that are not element-nodes, but attribute-nodes - * @throws IOException - * @throws COSVisitorException - * - */ - @Test - public void testAttributeRead() throws COSVisitorException, IOException { - - // test 1 has attributes - String bibtex = t2XMP(); - - writeManually(pdfFile, XMPUtilTest.bibtexXPacket(bibtex)); - - List l = XMPUtil.readXMP(pdfFile.getAbsoluteFile(), xmpPreferences); - Assert.assertEquals(1, l.size()); - BibEntry e = l.get(0); - - assertEqualsBibtexEntry(t2BibtexEntry(), e); - } - - @Test - public void testEmpty() throws Exception { - - Assert.assertEquals(Collections.emptyList(), XMPUtil.readXMP(pdfFile, xmpPreferences)); - - } - - /** - * Tests whether writing BibTex.xmp will preserve existing XMP-descriptions. - * - * @throws Exception (indicating an failure) - */ - @Test - public void testSimpleUpdate() throws Exception { - - String s = " " - + " Acrobat PDFMaker 7.0.7" - + " 2006-08-07T18:50:24+02:00" - + " 2006-08-07T14:44:24+02:00" - + " 2006-08-07T18:50:24+02:00" + " " - + " " - + " uuid:843cd67d-495e-4c1e-a4cd-64178f6b3299" - + " uuid:1e56b4c0-6782-440d-ba76-d2b3d87547d1" - + " " + " " + " 17" + " " - + " " + " " + " " + " application/pdf" - + ""; - - writeManually(pdfFile, XMPUtilTest.bibtexXPacket(s)); - - // Nothing there yet, but should not crash - Assert.assertEquals(Collections.emptyList(), XMPUtil.readXMP(pdfFile, xmpPreferences)); - - s = " " - + " Acrobat PDFMaker 7.0.7" - + " 2006-08-07T18:50:24+02:00" - + " 2006-08-07T14:44:24+02:00" - + " 2006-08-07T18:50:24+02:00" + " " - + " " - + " uuid:843cd67d-495e-4c1e-a4cd-64178f6b3299" - + " uuid:1e56b4c0-6782-440d-ba76-d2b3d87547d1" - + " " + " " + " 17" + " " - + " " + " " + " " + " application/pdf" - + " " + " " + " Questionnaire.pdf" - + " " + " " + ""; - - writeManually(pdfFile, XMPUtilTest.bibtexXPacket(s)); - - // Title is Questionnaire.pdf so the DublinCore fallback should hit - // in... - Assert.assertEquals(1, XMPUtil.readXMP(pdfFile, xmpPreferences).size()); - - { - // Now write new packet and check if it was correctly written - XMPUtil.writeXMP(pdfFile, t1BibtexEntry(), null, xmpPreferences); - - List l = XMPUtil.readXMP(pdfFile.getAbsoluteFile(), xmpPreferences); - Assert.assertEquals(1, l.size()); - BibEntry e = l.get(0); - - assertEqualsBibtexEntry(t1BibtexEntry(), e); - - // This is what we really want to test: Is the rest of the - // descriptions still there? - - try (PDDocument document = PDDocument.load(pdfFile.getAbsoluteFile())) { - - if (document.isEncrypted()) { - throw new IOException("Error: Cannot read metadata from encrypted document."); - } - PDDocumentCatalog catalog = document.getDocumentCatalog(); - PDMetadata metaRaw = catalog.getMetadata(); - - XMPMetadata meta; - if (metaRaw == null) { - meta = new XMPMetadata(); - } else { - meta = new XMPMetadata(XMLUtil.parse(metaRaw.createInputStream())); - } - meta.addXMLNSMapping(XMPSchemaBibtex.NAMESPACE, XMPSchemaBibtex.class); - - List schemas = meta.getSchemas(); - - Assert.assertEquals(4, schemas.size()); - - schemas = meta.getSchemasByNamespaceURI(XMPSchemaBibtex.NAMESPACE); - Assert.assertEquals(1, schemas.size()); - - schemas = meta.getSchemasByNamespaceURI(XMPSchemaDublinCore.NAMESPACE); - Assert.assertEquals(1, schemas.size()); - XMPSchemaDublinCore dc = (XMPSchemaDublinCore) schemas.get(0); - Assert.assertEquals("application/pdf", dc.getFormat()); - - schemas = meta.getSchemasByNamespaceURI(XMPSchemaBasic.NAMESPACE); - Assert.assertEquals(1, schemas.size()); - XMPSchemaBasic bs = (XMPSchemaBasic) schemas.get(0); - Assert.assertEquals("Acrobat PDFMaker 7.0.7", bs.getCreatorTool()); - - Calendar c = Calendar.getInstance(); - c.clear(); - c.set(Calendar.YEAR, 2006); - c.set(Calendar.MONTH, Calendar.AUGUST); - c.set(Calendar.DATE, 7); - c.set(Calendar.HOUR, 14); - c.set(Calendar.MINUTE, 44); - c.set(Calendar.SECOND, 24); - c.setTimeZone(TimeZone.getTimeZone("GMT+2")); - - Calendar other = bs.getCreateDate(); - - Assert.assertEquals(c.get(Calendar.YEAR), other.get(Calendar.YEAR)); - Assert.assertEquals(c.get(Calendar.MONTH), other.get(Calendar.MONTH)); - Assert.assertEquals(c.get(Calendar.DATE), other.get(Calendar.DATE)); - Assert.assertEquals(c.get(Calendar.HOUR), other.get(Calendar.HOUR)); - Assert.assertEquals(c.get(Calendar.MINUTE), other.get(Calendar.MINUTE)); - Assert.assertEquals(c.get(Calendar.SECOND), other.get(Calendar.SECOND)); - Assert.assertTrue(c.getTimeZone().hasSameRules(other.getTimeZone())); - - schemas = meta.getSchemasByNamespaceURI(XMPSchemaMediaManagement.NAMESPACE); - Assert.assertEquals(1, schemas.size()); - XMPSchemaMediaManagement mm = (XMPSchemaMediaManagement) schemas.get(0); - Assert.assertEquals("17", mm.getSequenceList("xapMM:VersionID").get(0)); - - } - } - - // Now alter the Bibtex entry, write it and do all the checks again - BibEntry toSet = t1BibtexEntry(); - toSet.setField("author", "Pokemon!"); - - XMPUtil.writeXMP(pdfFile, toSet, null, xmpPreferences); - - List l = XMPUtil.readXMP(pdfFile.getAbsoluteFile(), xmpPreferences); - Assert.assertEquals(1, l.size()); - BibEntry e = l.get(0); - - assertEqualsBibtexEntry(toSet, e); - - // This is what we really want to test: Is the rest of the - // descriptions still there? - - try (PDDocument document = PDDocument.load(pdfFile.getAbsoluteFile())) { - - if (document.isEncrypted()) { - throw new IOException("Error: Cannot read metadata from encrypted document."); - } - PDDocumentCatalog catalog = document.getDocumentCatalog(); - PDMetadata metaRaw = catalog.getMetadata(); - - XMPMetadata meta; - if (metaRaw == null) { - meta = new XMPMetadata(); - } else { - meta = new XMPMetadata(XMLUtil.parse(metaRaw.createInputStream())); - } - meta.addXMLNSMapping(XMPSchemaBibtex.NAMESPACE, XMPSchemaBibtex.class); - - List schemas = meta.getSchemas(); - - Assert.assertEquals(4, schemas.size()); - - schemas = meta.getSchemasByNamespaceURI(XMPSchemaBibtex.NAMESPACE); - Assert.assertEquals(1, schemas.size()); - - schemas = meta.getSchemasByNamespaceURI(XMPSchemaDublinCore.NAMESPACE); - Assert.assertEquals(1, schemas.size()); - XMPSchemaDublinCore dc = (XMPSchemaDublinCore) schemas.get(0); - Assert.assertEquals("application/pdf", dc.getFormat()); - - schemas = meta.getSchemasByNamespaceURI(XMPSchemaBasic.NAMESPACE); - Assert.assertEquals(1, schemas.size()); - XMPSchemaBasic bs = (XMPSchemaBasic) schemas.get(0); - Assert.assertEquals("Acrobat PDFMaker 7.0.7", bs.getCreatorTool()); - - Calendar c = Calendar.getInstance(); - c.clear(); - c.set(Calendar.YEAR, 2006); - c.set(Calendar.MONTH, 7); - c.set(Calendar.DATE, 7); - c.set(Calendar.HOUR, 14); - c.set(Calendar.MINUTE, 44); - c.set(Calendar.SECOND, 24); - c.setTimeZone(TimeZone.getTimeZone("GMT+2")); - - Calendar other = bs.getCreateDate(); - - Assert.assertEquals(c.get(Calendar.YEAR), other.get(Calendar.YEAR)); - Assert.assertEquals(c.get(Calendar.MONTH), other.get(Calendar.MONTH)); - Assert.assertEquals(c.get(Calendar.DATE), other.get(Calendar.DATE)); - Assert.assertEquals(c.get(Calendar.HOUR), other.get(Calendar.HOUR)); - Assert.assertEquals(c.get(Calendar.MINUTE), other.get(Calendar.MINUTE)); - Assert.assertEquals(c.get(Calendar.SECOND), other.get(Calendar.SECOND)); - Assert.assertTrue(c.getTimeZone().hasSameRules(other.getTimeZone())); - - schemas = meta.getSchemasByNamespaceURI(XMPSchemaMediaManagement.NAMESPACE); - Assert.assertEquals(1, schemas.size()); - XMPSchemaMediaManagement mm = (XMPSchemaMediaManagement) schemas.get(0); - Assert.assertEquals("17", mm.getSequenceList("xapMM:VersionID").get(0)); - - } - } - - /** - * Is XML in text properties properly escaped? - * - * @throws Exception - */ - @Test - public void testXMLEscape() throws Exception { - ParserResult result = parser.parse(new StringReader( - "@article{canh05," + " author = {Crowston, K. and Annabi, H. and Howison, J. and Masango, C.}," + "\n" - + " title = { \" bla \" '' '' && & for floss development: A model and propositions}," - + "\n" + " booktitle = {}," + "\n" + " year = {2005}," + "\n" - + " owner = {oezbek}," + "\n" + " timestamp = {2006.05.29}," + "\n" - + " url = {http://james.howison.name/publications.html}" + "\n" + "}")); - - Collection c = result.getDatabase().getEntries(); - Assert.assertEquals(1, c.size()); - - BibEntry e = c.iterator().next(); - - XMPUtil.writeXMP(pdfFile, e, null, xmpPreferences); - - List l = XMPUtil.readXMP(pdfFile.getAbsoluteFile(), xmpPreferences); - Assert.assertEquals(1, l.size()); - BibEntry x = l.get(0); - - assertEqualsBibtexEntry(e, x); - } - - public void assertEqualsBibtexEntry(BibEntry expected, BibEntry actual) { - Assert.assertNotNull(expected); - Assert.assertNotNull(actual); - Assert.assertEquals(expected.getCiteKeyOptional(), actual.getCiteKeyOptional()); - Assert.assertEquals(expected.getType(), actual.getType()); - - for (String field : expected.getFieldNames()) { - - if ("author".equalsIgnoreCase(field) || "editor".equalsIgnoreCase(field)) { - - AuthorList expectedAuthors = AuthorList.parse(expected.getField(field).get()); - AuthorList actualAuthors = AuthorList.parse(actual.getField(field).get()); - Assert.assertEquals(expectedAuthors, actualAuthors); - } else { - Assert.assertEquals("comparing " + field, expected.getField(field), - actual.getField(field)); - } - } - - Assert.assertEquals(expected.getFieldNames().size(), actual.getFieldNames().size()); - } - - /** - * @depends XMPUtilTest.testReadMultiple() - */ - @Test - public void testXMPreadString() throws Exception { - - ParserResult result = parser - .parse(new StringReader("@article{canh05," + " author = {Crowston, K. and Annabi, H.},\n" - + " title = {Title A}}\n" + "@inProceedings{foo," + " author={Norton Bar}}")); - - Collection c = result.getDatabase().getEntries(); - Assert.assertEquals(2, c.size()); - - String xmp = XMPUtil.toXMP(c, null, xmpPreferences); - - /* Test minimal syntaxical completeness */ - Assert.assertTrue(xmp.indexOf("xpacket") > 0); - Assert.assertTrue(xmp.indexOf("adobe:ns:meta") > 0); - Assert.assertTrue((xmp.indexOf("canh05") > 0) - || (xmp.indexOf("bibtex:bibtexkey=") > 0)); - Assert.assertTrue(xmp.indexOf("Norton Bar") > 0); - Assert.assertTrue((xmp.indexOf("id='W5M0MpCehiHzreSzNTczkc9d'?>") > 0) - || (xmp.indexOf("id=\"W5M0MpCehiHzreSzNTczkc9d\"?>") > 0)); - Assert.assertTrue((xmp.indexOf("xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'") > 0) - || (xmp.indexOf("xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"") > 0)); - Assert.assertTrue(xmp.indexOf(" 0); - Assert.assertTrue((xmp.indexOf("") > 0) || (xmp.indexOf("") > 0)); - - /* Test contents of string */ - writeManually(pdfFile, xmp); - - List l = XMPUtil.readXMP(pdfFile, xmpPreferences); - - Assert.assertEquals(2, l.size()); - - BibEntry a = l.get(0); - BibEntry b = l.get(1); - - if (a.getCiteKeyOptional().get().equals("foo")) { - BibEntry tmp = a; - a = b; - b = tmp; - } - - Assert.assertEquals(Optional.of("canh05"), a.getCiteKeyOptional()); - Assert.assertEquals("K. Crowston and H. Annabi", a.getField("author").get()); - Assert.assertEquals("Title A", a.getField("title").get()); - Assert.assertEquals("article", a.getType()); - - Assert.assertEquals(Optional.of("foo"), b.getCiteKeyOptional()); - Assert.assertEquals("Norton Bar", b.getField("author").get()); - Assert.assertEquals("inproceedings", b.getType()); - } - - /** - * Tests whether it is possible to read several BibtexEntries - * - * @throws Exception - */ - @Test - public void testReadMultiple() throws Exception { - - String bibtex = t2XMP() + t3XMP(); - writeManually(pdfFile, XMPUtilTest.bibtexXPacket(bibtex)); - - // Read from file - List l = XMPUtil.readXMP(pdfFile, xmpPreferences); - - Assert.assertEquals(2, l.size()); - - BibEntry a = l.get(0); - BibEntry b = l.get(1); - - if (a.getCiteKeyOptional().get().equals("Clarkson06")) { - BibEntry tmp = a; - a = b; - b = tmp; - } - - assertEqualsBibtexEntry(t2BibtexEntry(), a); - assertEqualsBibtexEntry(t3BibtexEntry(), b); - } - - /** - * Tests whether it is possible to write several Bibtexentries - * - * @throws TransformerException - * @throws IOException - */ - @Test - public void testWriteMultiple() throws IOException, TransformerException { - List l = new ArrayList<>(); - l.add(t2BibtexEntry()); - l.add(t3BibtexEntry()); - - XMPUtil.writeXMP(pdfFile, l, null, false, xmpPreferences); - - l = XMPUtil.readXMP(pdfFile, xmpPreferences); - - Assert.assertEquals(2, l.size()); - - BibEntry a = l.get(0); - BibEntry b = l.get(1); - - if (a.getCiteKeyOptional().get().equals("Clarkson06")) { - BibEntry tmp = a; - a = b; - b = tmp; - } - - assertEqualsBibtexEntry(t2BibtexEntry(), a); - assertEqualsBibtexEntry(t3BibtexEntry(), b); - } - - /** - * Tests whether a edit-protected PDF can be read - */ - @Test - public void testReadProtectedPDFHasMetaData() throws Exception { - try (InputStream is = XMPUtilTest.class.getResourceAsStream("/pdfs/write-protected.pdf")) { - Assert.assertTrue(XMPUtil.hasMetadata(is, xmpPreferences)); - } - } - - /** - * Tests whether a edit-protected PDF can be read - */ - @Test - public void testReadProtectedPDFHasCorrectMetaData() throws Exception { - try (InputStream is = XMPUtilTest.class.getResourceAsStream("/pdfs/write-protected.pdf")) { - List readEntries = XMPUtil.readXMP(is, xmpPreferences); - - BibEntry entry = new BibEntry(); - entry.setType("misc"); - entry.setField("author", "Firstname Lastname"); - List expected = Collections.singletonList(entry); - - Assert.assertEquals(expected, readEntries); - } - } - - @Test - public void testReadWriteDC() throws IOException, TransformerException { - List l = new ArrayList<>(); - l.add(t3BibtexEntry()); - - XMPUtil.writeXMP(pdfFile, l, null, true, xmpPreferences); - - try (PDDocument document = PDDocument.load(pdfFile.getAbsoluteFile())) { - if (document.isEncrypted()) { - Assert.fail("Cannot add metadata to encrypted document."); - } - - Assert.assertEquals("Kelly Clarkson and Ozzy Osbourne", document.getDocumentInformation().getAuthor()); - Assert.assertEquals("Hypersonic ultra-sound", document.getDocumentInformation().getTitle()); - Assert.assertEquals("Huey Duck and Dewey Duck and Louie Duck", - document.getDocumentInformation().getCustomMetadataValue("bibtex/editor")); - Assert.assertEquals("Clarkson06", - document.getDocumentInformation().getCustomMetadataValue("bibtex/bibtexkey")); - Assert.assertEquals("peanut, butter, jelly", document.getDocumentInformation().getKeywords()); - - assertEqualsBibtexEntry(t3BibtexEntry(), - XMPUtil.getBibtexEntryFromDocumentInformation(document.getDocumentInformation()).get()); - - PDDocumentCatalog catalog = document.getDocumentCatalog(); - PDMetadata metaRaw = catalog.getMetadata(); - - if (metaRaw == null) { - Assert.fail(); - return; - } - - XMPMetadata meta = new XMPMetadata(XMLUtil.parse(metaRaw.createInputStream())); - meta.addXMLNSMapping(XMPSchemaBibtex.NAMESPACE, XMPSchemaBibtex.class); - - // Check Dublin Core - List schemas = meta.getSchemasByNamespaceURI("http://purl.org/dc/elements/1.1/"); - Assert.assertEquals(1, schemas.size()); - - XMPSchemaDublinCore dcSchema = (XMPSchemaDublinCore) schemas.iterator().next(); - Assert.assertNotNull(dcSchema); - - Assert.assertEquals("Hypersonic ultra-sound", dcSchema.getTitle()); - Assert.assertEquals("1982-07", dcSchema.getSequenceList("dc:date").get(0)); - Assert.assertEquals("Kelly Clarkson", dcSchema.getCreators().get(0)); - Assert.assertEquals("Ozzy Osbourne", dcSchema.getCreators().get(1)); - Assert.assertEquals("Huey Duck", dcSchema.getContributors().get(0)); - Assert.assertEquals("Dewey Duck", dcSchema.getContributors().get(1)); - Assert.assertEquals("Louie Duck", dcSchema.getContributors().get(2)); - Assert.assertEquals("InProceedings".toLowerCase(), dcSchema.getTypes().get(0).toLowerCase()); - Assert.assertTrue(dcSchema.getRelationships().contains("bibtex/bibtexkey/Clarkson06")); - Assert.assertEquals("peanut", dcSchema.getSubjects().get(0)); - Assert.assertEquals("butter", dcSchema.getSubjects().get(1)); - Assert.assertEquals("jelly", dcSchema.getSubjects().get(2)); - - /** - * Bibtexkey, Journal, pdf, booktitle - */ - Assert.assertEquals(4, dcSchema.getRelationships().size()); - - assertEqualsBibtexEntry(t3BibtexEntry(), - XMPUtil.getBibtexEntryFromDublinCore(dcSchema, xmpPreferences).get()); - - } - - } - - @Test - public void testWriteSingleUpdatesDCAndInfo() throws IOException, TransformerException { - List l = new ArrayList<>(); - l.add(t3BibtexEntry()); - - XMPUtil.writeXMP(pdfFile, l, null, true, xmpPreferences); - - try (PDDocument document = PDDocument.load(pdfFile.getAbsoluteFile())) { - if (document.isEncrypted()) { - Assert.fail("Cannot add metadata to encrypted document."); - } - - Assert.assertEquals("Kelly Clarkson and Ozzy Osbourne", document.getDocumentInformation().getAuthor()); - Assert.assertEquals("Hypersonic ultra-sound", document.getDocumentInformation().getTitle()); - Assert.assertEquals("Huey Duck and Dewey Duck and Louie Duck", - document.getDocumentInformation().getCustomMetadataValue("bibtex/editor")); - Assert.assertEquals("Clarkson06", - document.getDocumentInformation().getCustomMetadataValue("bibtex/bibtexkey")); - Assert.assertEquals("peanut, butter, jelly", document.getDocumentInformation().getKeywords()); - - assertEqualsBibtexEntry(t3BibtexEntry(), - XMPUtil.getBibtexEntryFromDocumentInformation(document.getDocumentInformation()).get()); - - PDDocumentCatalog catalog = document.getDocumentCatalog(); - PDMetadata metaRaw = catalog.getMetadata(); - - if (metaRaw == null) { - Assert.fail(); - return; - } - - XMPMetadata meta = new XMPMetadata(XMLUtil.parse(metaRaw.createInputStream())); - meta.addXMLNSMapping(XMPSchemaBibtex.NAMESPACE, XMPSchemaBibtex.class); - - // Check Dublin Core - List schemas = meta.getSchemasByNamespaceURI("http://purl.org/dc/elements/1.1/"); - - Assert.assertEquals(1, schemas.size()); - - XMPSchemaDublinCore dcSchema = (XMPSchemaDublinCore) schemas.iterator().next(); - Assert.assertNotNull(dcSchema); - - Assert.assertEquals("Hypersonic ultra-sound", dcSchema.getTitle()); - Assert.assertEquals("1982-07", dcSchema.getSequenceList("dc:date").get(0)); - Assert.assertEquals("Kelly Clarkson", dcSchema.getCreators().get(0)); - Assert.assertEquals("Ozzy Osbourne", dcSchema.getCreators().get(1)); - Assert.assertEquals("Huey Duck", dcSchema.getContributors().get(0)); - Assert.assertEquals("Dewey Duck", dcSchema.getContributors().get(1)); - Assert.assertEquals("Louie Duck", dcSchema.getContributors().get(2)); - Assert.assertEquals("InProceedings".toLowerCase(), dcSchema.getTypes().get(0).toLowerCase()); - Assert.assertTrue(dcSchema.getRelationships().contains("bibtex/bibtexkey/Clarkson06")); - Assert.assertEquals("peanut", dcSchema.getSubjects().get(0)); - Assert.assertEquals("butter", dcSchema.getSubjects().get(1)); - Assert.assertEquals("jelly", dcSchema.getSubjects().get(2)); - - /** - * Bibtexkey, Journal, pdf, booktitle - */ - Assert.assertEquals(4, dcSchema.getRelationships().size()); - - assertEqualsBibtexEntry(t3BibtexEntry(), - XMPUtil.getBibtexEntryFromDublinCore(dcSchema, xmpPreferences).get()); - - } - } - - @Test - public void testReadRawXMP() throws IOException, TransformerException { - - ParserResult result = parser.parse(new StringReader( - "@article{canh05," + " author = {Crowston, K. and Annabi, H. and Howison, J. and Masango, C.},\n" - + " title = {Effective work practices for floss development: A model and propositions},\n" - + " booktitle = {Hawaii International Conference On System Sciences (HICSS)},\n" - + " year = {2005},\n" + " owner = {oezbek},\n" + " timestamp = {2006.05.29},\n" - + " url = {http://james.howison.name/publications.html}}")); - - Collection c = result.getDatabase().getEntries(); - Assert.assertEquals(1, c.size()); - - BibEntry e = c.iterator().next(); - - XMPUtil.writeXMP(pdfFile, e, null, xmpPreferences); - - Optional metadata = XMPUtil.readRawXMP(pdfFile); - - Assert.assertTrue(metadata.isPresent()); - - List schemas = metadata.get().getSchemas(); - Assert.assertEquals(2, schemas.size()); - schemas = metadata.get().getSchemasByNamespaceURI(XMPSchemaBibtex.NAMESPACE); - Assert.assertEquals(1, schemas.size()); - XMPSchemaBibtex bib = (XMPSchemaBibtex) schemas.get(0); - - List authors = bib.getSequenceList("author"); - Assert.assertEquals(4, authors.size()); - Assert.assertEquals("K. Crowston", authors.get(0)); - Assert.assertEquals("H. Annabi", authors.get(1)); - Assert.assertEquals("J. Howison", authors.get(2)); - Assert.assertEquals("C. Masango", authors.get(3)); - - Assert.assertEquals("article", bib.getTextProperty("entrytype")); - Assert.assertEquals("Effective work practices for floss development: A model and propositions", - bib.getTextProperty("title")); - Assert.assertEquals("Hawaii International Conference On System Sciences (HICSS)", - bib.getTextProperty("booktitle")); - Assert.assertEquals("2005", bib.getTextProperty("year")); - Assert.assertEquals("oezbek", bib.getTextProperty("owner")); - Assert.assertEquals("http://james.howison.name/publications.html", bib.getTextProperty("url")); - - } - - /** - * Test whether the command-line client works correctly with writing a single entry - * @throws IOException - * @throws TransformerException - * @throws COSVisitorException - * - - */ - @Test - public void testCommandLineSingleBib() throws IOException, TransformerException, COSVisitorException { - - // First check conversion from .bib to .xmp - File tempBib = tempFolder.newFile("JabRef.bib"); - try (BufferedWriter fileWriter = Files.newBufferedWriter(tempBib.toPath(), StandardCharsets.UTF_8)) { - fileWriter.write(t1BibtexString()); - fileWriter.close(); - - try (ByteArrayOutputStream s = new ByteArrayOutputStream()) { - PrintStream oldOut = System.out; - System.setOut(new PrintStream(s)); - XMPUtilMain.main(new String[] {tempBib.getAbsolutePath()}); - System.setOut(oldOut); - String xmp = s.toString(); - - writeManually(pdfFile, xmp); - } - List l = XMPUtil.readXMP(pdfFile, xmpPreferences); - Assert.assertEquals(1, l.size()); - assertEqualsBibtexEntry(t1BibtexEntry(), l.get(0)); - - } - } - - /** - * @throws IOException - * @throws TransformerException - * @throws COSVisitorException - * @depends XMPUtil.writeXMP - */ - @Test - public void testCommandLineSinglePdf() throws IOException, TransformerException, COSVisitorException { - { - // Write XMP to file - - BibEntry e = t1BibtexEntry(); - - XMPUtil.writeXMP(pdfFile, e, null, xmpPreferences); - - try (ByteArrayOutputStream s = new ByteArrayOutputStream()) { - PrintStream oldOut = System.out; - System.setOut(new PrintStream(s)); - XMPUtilMain.main(new String[] {pdfFile.getAbsolutePath()}); - System.setOut(oldOut); - String bibtex = s.toString(); - - ParserResult result = new BibtexParser(importFormatPreferences, fileMonitor).parse(new StringReader(bibtex)); - Collection c = result.getDatabase().getEntries(); - Assert.assertEquals(1, c.size()); - BibEntry x = c.iterator().next(); - - assertEqualsBibtexEntry(e, x); - } - } - // Write XMP to file - BibEntry e = t1BibtexEntry(); - - XMPUtil.writeXMP(pdfFile, e, null, xmpPreferences); - - try (ByteArrayOutputStream s = new ByteArrayOutputStream()) { - PrintStream oldOut = System.out; - System.setOut(new PrintStream(s)); - XMPUtilMain.main(new String[] {"-x", pdfFile.getAbsolutePath()}); - System.setOut(oldOut); - s.close(); - String xmp = s.toString(); - - /* Test minimal syntaxical completeness */ - Assert.assertTrue(xmp.indexOf("xpacket") > 0); - Assert.assertTrue(xmp.indexOf("adobe:ns:meta") > 0); - Assert.assertTrue((xmp.indexOf("canh05") > 0) - || (xmp.indexOf("bibtex:bibtexkey=") > 0)); - Assert.assertTrue(xmp.indexOf("K. Crowston") > 0); - Assert.assertTrue((xmp.indexOf("id='W5M0MpCehiHzreSzNTczkc9d'?>") > 0) - || (xmp.indexOf("id=\"W5M0MpCehiHzreSzNTczkc9d\"?>") > 0)); - Assert.assertTrue((xmp.indexOf("xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'") > 0) - || (xmp.indexOf("xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"") > 0)); - Assert.assertTrue(xmp.indexOf(" 0); - Assert.assertTrue((xmp.indexOf("") > 0) || (xmp.indexOf("") > 0)); - - /* Test contents of string */ - writeManually(pdfFile, xmp); - List l = XMPUtil.readXMP(pdfFile, xmpPreferences); - Assert.assertEquals(1, l.size()); - - assertEqualsBibtexEntry(t1BibtexEntry(), l.get(0)); - } - } - - /** - * Test whether the command-line client can pick one of several entries from a bibtex file - * @throws IOException - * @throws TransformerException - */ - @Test - public void testCommandLineByKey() throws IOException, TransformerException { - File tempBib = tempFolder.newFile("JabRef.bib"); - try (BufferedWriter fileWriter = Files.newBufferedWriter(tempBib.toPath(), StandardCharsets.UTF_8)) { - fileWriter.write(t1BibtexString()); - fileWriter.write(t2BibtexString()); - } - - PrintStream sysOut = System.out; - - // First try canh05 - try (ByteArrayOutputStream s = new ByteArrayOutputStream()) { - System.setOut(new PrintStream(s)); - XMPUtilMain.main(new String[]{"canh05", tempBib.getAbsolutePath(), pdfFile.getAbsolutePath()}); - } finally { - System.setOut(sysOut); - } - - // PDF should be annotated: - List l = XMPUtil.readXMP(pdfFile, xmpPreferences); - Assert.assertEquals(1, l.size()); - assertEqualsBibtexEntry(t1BibtexEntry(), l.get(0)); - - // Now try OezbekC06 - try (ByteArrayOutputStream s = new ByteArrayOutputStream()) { - System.setOut(new PrintStream(s)); - try { - XMPUtilMain.main(new String[]{"OezbekC06", tempBib.getAbsolutePath(), pdfFile.getAbsolutePath()}); - } finally { - System.setOut(sysOut); - } - } - - // PDF should be annotated: - l = XMPUtil.readXMP(pdfFile, xmpPreferences); - Assert.assertEquals(1, l.size()); - assertEqualsBibtexEntry(t2BibtexEntry(), l.get(0)); - } - - /** - * Test whether the command-line client can deal with several bibtex entries. - * @throws IOException - * @throws TransformerException - */ - @Test - public void testCommandLineSeveral() throws IOException, TransformerException { - - File tempBib = tempFolder.newFile("JabRef.bib"); - - try (BufferedWriter fileWriter = Files.newBufferedWriter(tempBib.toPath(), StandardCharsets.UTF_8)) { - - fileWriter.write(t1BibtexString()); - fileWriter.write(t3BibtexString()); - fileWriter.close(); - - try (ByteArrayOutputStream s = new ByteArrayOutputStream()) { - PrintStream oldOut = System.out; - System.setOut(new PrintStream(s)); - XMPUtilMain.main(new String[] {tempBib.getAbsolutePath(), pdfFile.getAbsolutePath()}); - System.setOut(oldOut); - } - List l = XMPUtil.readXMP(pdfFile, xmpPreferences); - - Assert.assertEquals(2, l.size()); - - BibEntry a = l.get(0); - BibEntry b = l.get(1); - - if (a.getCiteKeyOptional().get().equals("Clarkson06")) { - BibEntry tmp = a; - a = b; - b = tmp; - } - - BibEntry t1 = t1BibtexEntry(); - BibEntry t3 = t3BibtexEntry(); - - // Writing and reading will resolve strings! - t3.setField("month", "July"); - - assertEqualsBibtexEntry(t1, a); - assertEqualsBibtexEntry(t3, b); - } - } - - /** - * Test that readXMP and writeXMP work together. - * @throws IOException - * @throws TransformerException - * - * @throws Exception - */ - @Test - public void testResolveStrings() throws IOException, TransformerException { - ParserResult original = parser - .parse(new StringReader("@string{ crow = \"Crowston, K.\"}\n" + "@string{ anna = \"Annabi, H.\"}\n" - + "@string{ howi = \"Howison, J.\"}\n" + "@string{ masa = \"Masango, C.\"}\n" - + "@article{canh05," + " author = {#crow# and #anna# and #howi# and #masa#}," + "\n" - + " title = {Effective work practices for floss development: A model and propositions}," + "\n" - + " booktitle = {Hawaii International Conference On System Sciences (HICSS)}," + "\n" - + " year = {2005}," + "\n" + " owner = {oezbek}," + "\n" + " timestamp = {2006.05.29}," - + "\n" + " url = {http://james.howison.name/publications.html}" + "\n" + "}")); - - Collection c = original.getDatabase().getEntries(); - Assert.assertEquals(1, c.size()); - - BibEntry e = c.iterator().next(); - - XMPUtil.writeXMP(pdfFile, e, original.getDatabase(), xmpPreferences); - - List l = XMPUtil.readXMP(pdfFile.getAbsoluteFile(), xmpPreferences); - Assert.assertEquals(1, l.size()); - BibEntry x = l.get(0); - - Assert.assertEquals(AuthorList.parse("Crowston, K. and Annabi, H. and Howison, J. and Masango, C."), - AuthorList.parse(x.getField("author").get())); - } - - @Test(expected = EncryptedPdfsNotSupportedException.class) - public void expectedEncryptionNotSupportedExceptionAtRead() throws IOException { - try (InputStream is = XMPUtilTest.class.getResourceAsStream("/pdfs/encrypted.pdf")) { - XMPUtil.readXMP(is, xmpPreferences); - } - } - - @Test(expected = EncryptedPdfsNotSupportedException.class) - public void expectedEncryptionNotSupportedExceptionAtWrite() throws IOException, TransformerException { - XMPUtil.writeXMP("src/test/resources/pdfs/encrypted.pdf", t1BibtexEntry(), null, xmpPreferences); - } - - /** - * A better testcase for resolveStrings. Makes sure that also the document information and dublin core are written - * correctly. - *

- * Data was contributed by Philip K.F. Hölzenspies (p.k.f.holzenspies [at] utwente.nl). - * - * @throws IOException - * @throws TransformerException - */ - @Test - public void testResolveStrings2() throws IOException, TransformerException { - - try (BufferedReader fr = Files.newBufferedReader(Paths.get("src/test/resources/org/jabref/util/twente.bib"), - StandardCharsets.UTF_8)) { - ParserResult result = new BibtexParser(importFormatPreferences, fileMonitor).parse(fr); - - Assert.assertEquals("Arvind", result.getDatabase().resolveForStrings("#Arvind#")); - - AuthorList originalAuthors = AuthorList.parse( - "Patterson, David and Arvind and Asanov\\'\\i{}c, Krste and Chiou, Derek and Hoe, James and Kozyrakis, Christos and Lu, S{hih-Lien} and Oskin, Mark and Rabaey, Jan and Wawrzynek, John"); - - try { - XMPUtil.writeXMP(pdfFile, result.getDatabase().getEntryByKey("Patterson06").get(), - result.getDatabase(), xmpPreferences); - - // Test whether we the main function can load the bibtex correctly - BibEntry b = XMPUtil.readXMP(pdfFile, xmpPreferences).get(0); - Assert.assertNotNull(b); - Assert.assertEquals(originalAuthors, AuthorList.parse(b.getField("author").get())); - - // Next check from Document Information - try (PDDocument document = PDDocument.load(pdfFile.getAbsoluteFile())) { - - Assert.assertEquals(originalAuthors, - AuthorList.parse(document.getDocumentInformation().getAuthor())); - - b = XMPUtil.getBibtexEntryFromDocumentInformation(document.getDocumentInformation()).get(); - Assert.assertEquals(originalAuthors, AuthorList.parse(b.getField("author").get())); - - // Now check from Dublin Core - PDDocumentCatalog catalog = document.getDocumentCatalog(); - PDMetadata metaRaw = catalog.getMetadata(); - - if (metaRaw == null) { - Assert.fail(); - return; // To avoid warnings - } - - XMPMetadata meta = new XMPMetadata(XMLUtil.parse(metaRaw.createInputStream())); - meta.addXMLNSMapping(XMPSchemaBibtex.NAMESPACE, XMPSchemaBibtex.class); - - List schemas = meta.getSchemasByNamespaceURI("http://purl.org/dc/elements/1.1/"); - - Assert.assertEquals(1, schemas.size()); - - XMPSchemaDublinCore dcSchema = (XMPSchemaDublinCore) schemas.iterator().next(); - Assert.assertNotNull(dcSchema); - - Assert.assertEquals("David Patterson", dcSchema.getCreators().get(0)); - Assert.assertEquals("Arvind", dcSchema.getCreators().get(1)); - Assert.assertEquals("Krste Asanov\\'\\i{}c", dcSchema.getCreators().get(2)); - - b = XMPUtil.getBibtexEntryFromDublinCore(dcSchema, xmpPreferences).get(); - Assert.assertNotNull(b); - Assert.assertEquals(originalAuthors, AuthorList.parse(b.getField("author").get())); - } - } finally { - if (!pdfFile.delete()) { - System.err.println("Cannot delete temporary file"); - } - } - } - } - -} diff --git a/src/test/java/org/jabref/logic/xmp/XmpUtilReaderTest.java b/src/test/java/org/jabref/logic/xmp/XmpUtilReaderTest.java new file mode 100644 index 00000000000..629d6982466 --- /dev/null +++ b/src/test/java/org/jabref/logic/xmp/XmpUtilReaderTest.java @@ -0,0 +1,111 @@ +package org.jabref.logic.xmp; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Collections; +import java.util.List; +import java.util.Optional; + +import org.jabref.logic.importer.ImportFormatPreferences; +import org.jabref.logic.importer.ParseException; +import org.jabref.logic.importer.fileformat.BibtexParser; +import org.jabref.model.entry.BibEntry; +import org.jabref.model.util.DummyFileUpdateMonitor; +import org.jabref.model.util.FileUpdateMonitor; + +import com.google.common.io.Resources; +import org.apache.xmpbox.XMPMetadata; +import org.apache.xmpbox.schema.DublinCoreSchema; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.mockito.Answers; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class XmpUtilReaderTest { + + @Rule public TemporaryFolder tempFolder = new TemporaryFolder(); + + private static final FileUpdateMonitor fileMonitor = new DummyFileUpdateMonitor(); + + private XmpPreferences xmpPreferences; + + private BibtexParser parser; + + /** + * Create a temporary PDF-file with a single empty page. + */ + @Before + public void setUp() { + ImportFormatPreferences importFormatPreferences = mock(ImportFormatPreferences.class, Answers.RETURNS_DEEP_STUBS); + when(importFormatPreferences.getEncoding()).thenReturn(StandardCharsets.UTF_8); + xmpPreferences = mock(XmpPreferences.class); + // The code assumes privacy filters to be off + when(xmpPreferences.isUseXMPPrivacyFilter()).thenReturn(false); + + when(xmpPreferences.getKeywordSeparator()).thenReturn(','); + + parser = new BibtexParser(importFormatPreferences, fileMonitor); + } + + /** + * Tests reading of dublinCore metadata. + */ + @Test + public void testReadArticleDublinCoreReadRawXmp() throws IOException, URISyntaxException, ParseException { + Path path = Paths.get(XmpUtilShared.class.getResource("article_dublinCore.pdf").toURI()); + List meta = XmpUtilReader.readRawXmp(path); + + DublinCoreSchema dcSchema = meta.get(0).getDublinCoreSchema(); + DublinCoreExtractor dcExtractor = new DublinCoreExtractor(dcSchema, xmpPreferences, new BibEntry()); + Optional entry = dcExtractor.extractBibtexEntry(); + String bibString = Resources.toString(XmpUtilShared.class.getResource("article_dublinCore.bib"), StandardCharsets.UTF_8); + Optional entryFromBibFile = parser.parseSingleEntry(bibString); + + Assert.assertEquals(entryFromBibFile.get(), entry.get()); + } + + /** + * Tests reading of dublinCore metadata. + */ + @Test + public void testReadArticleDublinCoreReadXmp() throws IOException, URISyntaxException, ParseException { + List entries = XmpUtilReader.readXmp(Paths.get(XmpUtilShared.class.getResource("article_dublinCore.pdf").toURI()), xmpPreferences); + BibEntry entry = entries.get(0); + + String bibString = Resources.toString(XmpUtilShared.class.getResource("article_dublinCore.bib"), StandardCharsets.UTF_8); + Optional entryFromBibFile = parser.parseSingleEntry(bibString); + + Assert.assertEquals(entryFromBibFile.get(), entry); + } + + /** + * Tests an pdf file with an empty metadata section. + */ + @Test + public void testReadEmtpyMetadata() throws IOException, URISyntaxException { + List entries = XmpUtilReader.readXmp(Paths.get(XmpUtilShared.class.getResource("empty_metadata.pdf").toURI()), xmpPreferences); + Assert.assertEquals(Collections.EMPTY_LIST, entries); + } + + /** + * Test non XMP metadata. Metadata are included in the PDInformation + */ + @Test + public void testReadPDMetadata() throws IOException, URISyntaxException, ParseException { + List entries = XmpUtilReader.readXmp(Paths.get(XmpUtilShared.class.getResource("PD_metadata.pdf").toURI()), xmpPreferences); + + String bibString = Resources.toString(XmpUtilShared.class.getResource("PD_metadata.bib"), StandardCharsets.UTF_8); + Optional entryFromBibFile = parser.parseSingleEntry(bibString); + + Assert.assertEquals(entryFromBibFile.get(), entries.get(0)); + } + +} diff --git a/src/test/java/org/jabref/logic/xmp/XmpUtilWriterTest.java b/src/test/java/org/jabref/logic/xmp/XmpUtilWriterTest.java new file mode 100644 index 00000000000..7037c2a57b1 --- /dev/null +++ b/src/test/java/org/jabref/logic/xmp/XmpUtilWriterTest.java @@ -0,0 +1,147 @@ +package org.jabref.logic.xmp; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.List; + +import javax.xml.transform.TransformerException; + +import org.jabref.model.entry.BibEntry; +import org.jabref.model.entry.Month; + +import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.pdmodel.PDPage; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class XmpUtilWriterTest { + + @Rule public TemporaryFolder tempFolder = new TemporaryFolder(); + + private XmpPreferences xmpPreferences; + + private static BibEntry olly2018; + private static BibEntry toral2006; + private static BibEntry vapnik2000; + + private void initBibEntries() { + + olly2018 = new BibEntry(); + olly2018.setType("article"); + olly2018.setCiteKey("Olly2018"); + olly2018.setField("author", "Olly and Johannes"); + olly2018.setField("title", "Stefan's palace"); + olly2018.setField("journal", "Test Journal"); + olly2018.setField("volume", "1"); + olly2018.setField("number", "1"); + olly2018.setField("pages", "1-2"); + olly2018.setMonth(Month.MARCH); + olly2018.setField("issn", "978-123-123"); + olly2018.setField("note", "NOTE"); + olly2018.setField("abstract", "ABSTRACT"); + olly2018.setField("comment", "COMMENT"); + olly2018.setField("doi", "10/3212.3123"); + olly2018.setField("file", ":article_dublinCore.pdf:PDF"); + olly2018.setField("groups", "NO"); + olly2018.setField("howpublished", "online"); + olly2018.setField("keywords", "k1, k2"); + olly2018.setField("owner", "me"); + olly2018.setField("review", "review"); + olly2018.setField("url", "https://www.olly2018.edu"); + + toral2006 = new BibEntry(); + toral2006.setType("InProceedings"); + toral2006.setField("author", "Toral, Antonio and Munoz, Rafael"); + toral2006.setField("title", "A proposal to automatically build and maintain gazetteers for Named Entity Recognition by using Wikipedia"); + toral2006.setField("booktitle", "Proceedings of EACL"); + toral2006.setField("pages", "56--61"); + toral2006.setField("eprinttype", "asdf"); + toral2006.setField("owner", "Ich"); + toral2006.setField("url", "www.url.de"); + + vapnik2000 = new BibEntry(); + vapnik2000.setType("Book"); + vapnik2000.setCiteKey("vapnik2000"); + vapnik2000.setField("title", "The Nature of Statistical Learning Theory"); + vapnik2000.setField("publisher", "Springer Science + Business Media"); + vapnik2000.setField("author", "Vladimir N. Vapnik"); + vapnik2000.setField("doi", "10.1007/978-1-4757-3264-1"); + vapnik2000.setField("owner", "Ich"); + } + + /** + * Create a temporary PDF-file with a single empty page. + */ + @Before + public void setUp() { + + xmpPreferences = mock(XmpPreferences.class); + // The code assumes privacy filters to be off + when(xmpPreferences.isUseXMPPrivacyFilter()).thenReturn(false); + + when(xmpPreferences.getKeywordSeparator()).thenReturn(','); + + this.initBibEntries(); + } + + /** + * Test for writing a PDF file with a single DublinCore metadata entry. + */ + @Test + public void testWriteXmp() throws IOException, TransformerException { + + File pdfFile = this.createDefaultFile("JabRef_writeSingle.pdf"); + + // read a bib entry from the tests before + BibEntry entry = vapnik2000; + entry.setCiteKey("WriteXMPTest"); + entry.setId("ID4711"); + + // write the changed bib entry to the create PDF + XmpUtilWriter.writeXmp(pdfFile.getAbsolutePath(), entry, null, xmpPreferences); + + // read entry again + List entriesWritten = XmpUtilReader.readXmp(pdfFile.getPath(), xmpPreferences); + BibEntry entryWritten = entriesWritten.get(0); + + // compare the two entries + Assert.assertEquals(entry, entryWritten); + + } + + /** + * Test, which writes multiple metadata entries to a PDF and reads them again to test the size. + */ + @Test + public void testWriteMultipleBibEntries() throws IOException, TransformerException { + + File pdfFile = this.createDefaultFile("JabRef_writeMultiple.pdf"); + + List entries = Arrays.asList(olly2018, vapnik2000, toral2006); + + XmpUtilWriter.writeXmp(Paths.get(pdfFile.getAbsolutePath()), entries, null, xmpPreferences); + + List entryList = XmpUtilReader.readXmp(Paths.get(pdfFile.getAbsolutePath()), xmpPreferences); + Assert.assertEquals(3, entryList.size()); + + } + + private File createDefaultFile(String fileName) throws IOException { + // create a default PDF + File pdfFile = tempFolder.newFile(fileName); + try (PDDocument pdf = new PDDocument()) { + // Need a single page to open in Acrobat + pdf.addPage(new PDPage()); + pdf.save(pdfFile.getPath()); + } + + return pdfFile; + } +} diff --git a/src/test/resources/org/jabref/logic/xmp/JabRef_multipleMetaEntries.pdf b/src/test/resources/org/jabref/logic/xmp/JabRef_multipleMetaEntries.pdf new file mode 100644 index 0000000000000000000000000000000000000000..c5bde94e758eb094836f238ed0ee0bdce7e517bb GIT binary patch literal 5197 zcmdT|OK;;g5WeeI5DtQFQOK0!S8O<5*iM3dE7PvljnlvW`1^OmMivs2&qlXv;PEP? z2oH%OzL**K1Ch zs_c=jfH8TwYb1;(K8xns&?uCQ&*0z4Wt6)V{eT8>#5j#2bVEHxK=GI=k`}F9xy~^vJVRV^UnJy?uOz)V{mNzFnxAffpyodtFT-lAn zo?Y#X()h9CNZ(gEWfKJC6FxhyEKQG2N$jgiuQcc!^RQqj3D%Y~+B@b!y0a;xvUe1x z63GH%mbO}aDr7)ZkA$HQSg4N#4!vn2ki9A}YY54g{oIadggdsR-Js`MQ;EV^PmLvp z3e^7&0n$@_L-&`q$$>RkZ~PFz(kf(o2fC*cDgwdP9G?V4o|NEbQN+`Z!Kswv>elJ?2Dz8-6OwS zel-$B@#Hgg3$XeezPzWag^=E}d6@AW$d1EK?Kq%)+9^%hAukj#-8&?HLNlPlz8`@6 z{W~!y96Hl|o|IBhd#o;cc^kBY!-YCg@aa%NN)d@8GJz(LxaycY1&xV22W;yQZ55plNmPzeHp|sf+t~s_-ttCfp`(2@ueWSA1Px0kg zNOzCH|ETh4eE4oC6T1mCPDy^_dnsHBpRjxu=?~V+{_whllUu0V ztlDFXkLqI)r3GKRC zp$F=U8E45C?PP`Y&|-!@vPTx`vBk0Vy$FTh2-x28LOLFEZZ|bvfVWf)%m;c#7jGsC z@UR(5!2IdFvPeb_dKQ%pEwZVUo{FqzALC@mrH3YZj0N!>+0lWr$-)9$UHX5}C0&;fQU{ha+uSxZKYnRlpU|zP(Wwm!n zb(ke>xS$L}cPf){-GdM?;?V;i1HZjMpSl-L<8m-)_Rso_dfT@9wTsrUb#Z2244r{B qXk7Ks%Pg?!5qqMrIQ*7R1=0h(hja`C9dWYqhSg{pr>B>9SH?erKi*0J literal 0 HcmV?d00001 diff --git a/src/test/resources/org/jabref/logic/xmp/PD_metadata.bib b/src/test/resources/org/jabref/logic/xmp/PD_metadata.bib new file mode 100644 index 00000000000..67ba5a1888b --- /dev/null +++ b/src/test/resources/org/jabref/logic/xmp/PD_metadata.bib @@ -0,0 +1,6 @@ +@misc{, + abstract = {how to annotate a pdf}, + author = {Chris}, + keywords = {pdf, annotation}, + title = {The best Pdf ever} +} \ No newline at end of file diff --git a/src/test/resources/org/jabref/logic/xmp/PD_metadata.pdf b/src/test/resources/org/jabref/logic/xmp/PD_metadata.pdf new file mode 100644 index 0000000000000000000000000000000000000000..c4b623e4e75bfdaee0fc97cc0360acb08f66af6f GIT binary patch literal 8952 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 literal 0 HcmV?d00001 diff --git a/src/test/resources/org/jabref/logic/xmp/article_dublinCore.bib b/src/test/resources/org/jabref/logic/xmp/article_dublinCore.bib new file mode 100644 index 00000000000..905c5e53dcb --- /dev/null +++ b/src/test/resources/org/jabref/logic/xmp/article_dublinCore.bib @@ -0,0 +1,23 @@ +@Article{Olly2018, + author = {Olly and Johannes}, + title = {Stefan's palace}, + journal = {Test Journal}, + year = {2018}, + volume = {1}, + number = {1}, + pages = {1-2}, + month = {March}, + issn = {978-123-123}, + note = {That's a note}, + abstract = {That's an abstract}, + comment = {That's a comment}, + doi = {10/3212.3123}, + file = {:paper.pdf:PDF}, + groups = {NO}, + howpublished = {Online}, + keywords = {Keyword1, Keyword2}, + owner = {Me}, + review = {Here are the reviews}, + timestamp = {2018-02-15}, + url = {https://www.olly2018.edu}, +} \ No newline at end of file diff --git a/src/test/resources/org/jabref/logic/xmp/article_dublinCore.pdf b/src/test/resources/org/jabref/logic/xmp/article_dublinCore.pdf new file mode 100644 index 0000000000000000000000000000000000000000..5cb2297b8bcfb7b5f6e43ab7f4533eab1fe65c98 GIT binary patch literal 311223 zcmeFZc_7r?_c%UwCK06&nozbdGiJt&E&G;zUs?RT2{x$$dA&`hr??AYY4qV+Sno2^b8xa}A;81_Kx*gG3(=ayAo>FS2pscWPY+I__(IKV zg7+mc48j=!p)`b|ZE$cjf=Ka2ScV1=DWGj7AR?I&OhPC+GDvVLurDlEu`qkP?|3tp}1H=Z9*)T&`S+~jv5mgKs;kD zG!lhJqLG>?tcC^_6OBlvl6(>Bro>=62?*k3;-+RA9vtiqbsWg!6hNjU z!2c|{HX&R{G&-bL4K)-7g(aYISXHzdZb@FmRz;|rR^$j00!V^WHzs+LiIlBMh#)GF z5kMyq5fO_FaB65Zr~}?)Zw4t!4sGg3h7_ztB?9fJf#$S;y|CAlC=6OO1F{rF0~&+u z6AUTtCv`w*BsJVSm`o1f6;Z0cbuS_`I6MT%{u{55Pzo>zMQb9>CxD#=jTAv9 zMIscBm@fx8RO4hlj(E{LXn_}S4E*UpkMY%-%v7W4ymqzMxoU-{#Ho| zh3sX?W)aXUJ1v6@W*LJRLS^Yp6^T|wVc8KvBbnx5{Tr1(Ei{}8EY-%A9W|T=loh~W zQ0ZFg>XDI=YN23$L8?|G`G&J2`hYZ0OZ|21JDx3Dx}S$>1*F2Ga^4F|Mn zFk{GIws_*9iH;yZ&uwhvkQe!#{FmD>CDXu&qL2^`T-}NYy+CdXyeu*QB?shzmKYfW zUC|LJmdE;q0{NaL6i0-*S*TMeT-|s{G<8!lgIzMnGc93TktqJaFfd3IcF8*~c`&BO zVNL^eH)|`XXTaHzh#|}2I-8>)k3wP~yh;9KimvQ*%^g_;*;iNA6>E*OrW%m~$mTIL zl4FdGlTS>L55ZSL>z%ppHbVqtU7WLzNy)VGyHKDRem&lSMW_Wj-`A zmFc5djr#ihhD3ih&|>4kWW6P4s-q5Z1OTXmOFvA?Ur6XbAhAH~+;!CdAO$2DSa(Ql?3v6R zNnvcDUt&SiLKUf@ibOdfky_0ERgfr9__rdkb7G3{TXRtRG*U1T(lc9w|4}t8@1o9f ze(I<{wERonMO>!KQwJXJpCGgRnEIc5+dm;^_w?#4NB>XASpN5)b%*Je)tO%TpRk6! zusWL){wFk$!&U#y{r(dwXpL0=eTn=hWQ$9dI{S+CPw0NG0_rTggcgB+LdRSj)U8SX z1edjDsN2~76J+2Q)c@T|@=xf0uJ`Itj0bhGhM~sC4i(N`vPxE_9K&MdhD?S6Q8Ya z$z4Ju3@A4Kdp8V%8El}RQX+zh6n|aWC{mW`Mp_45Z_;m z3R~Mu1+r7KY4u;lS(=l-!uWqK(VyCff`!Id6ItXx?omi~;O`Rad z{k!<=7R4sM-eM&DZ$)IMV=0ZDIV9WvuA9I%p{4tO*G*oKT*G<-9%eH}KF4in4*d2p69rd3(YUu6fz8vHnb!8(LciqdO6eMf! zzLboFau!P|fM2-{DEmNRKzm>WYB34wK%#@ZlMhIQq82lu)+Apt(J(X$;R&TLumr3c zS`&xBV^C^%!Zs+SN`o>hi#b&T3fO*t90`h<9Yvs+Nm2G(1e7-U&w@aCQ;-*76NH&? z0qMs7ks!=G4M-V6ToGty(glHLO3N-5Gd1&5E>=d?0;C0@1bR_Ni(Oty z8RPKfo<*2 z+z~62gkDTOGc!qOR_1vzlccK2mXl&8j+UfgWv|do{UXq;EEbxj9u1~?z-U^LL&(th zDH@0Rs5(NTDIpXYMDJjd8cOLmg+anCab8R+p^<1!I7mJPGeBxn-4x^oNX8@|kVI$C zB}F}-bhkb60w;8*qsY!SbKr>hUm_;OCvHzhC|KKCYv@h{&7ZxBt;ChTX{MDg%r9GU zc2i3(rgnaggqAf}!CkiwmL``TBAf0SIU{^~vrb>_EmxCsIgeULTJAZXD_vQB{cyUA z`6->?w1FpkF6Y?R(C@S+p~uu!w&iz+W!4u>x&Da$Ea6*atYq&|Vt*i2R()$4S^d^0 z`vXrAT+h-Uim%@$AZRMybfizt=zCSG)AP$tF^#6(dk$cU(x2jQdng~1E!z|w9qRPj z#C?_T{?)e?z1A<=VZH3z&B+_gQf zdFxjDlaVW(YSMMiie_K!g_52#wp{;W{IKTc^ zeBhoskF-fP_fy-q2?ol# z?Gyf&HoH_EZcJ%=ubWphUcBRctM)nF@Q3$f#NFbRy2o^}?Ft(oMPa5l%D<6H%C2vY zQcP5mftwX`WPTIkp4UFoUc{kpq`0%d?K;0XAOE+m(j=SBdtv?-vb#>*yQv!*_^wa$ z1?=>xQP=G!PwG#d`U~UL8Fr$!QD~~7sWzhOX*RZLdZ9O>`v6&6CV0O4_^Ijq7Ej9N zx&GZ7ZxzWP{)&8o$_c_CgkZlcU-(c*X(qe04Kt+uG$e9NI>=mlrQE>UulT-;a6`9F6#H zyvnsd=C>>O%hU@0f$}4?{YnI_B-^LmsZYf0%v3nHm`QaX5D=S7nEfcz{g%5^V~E&} zUnyO%?P23~45z9pg8yAip-kYaZ{@Gl_%$#-8zw%+cq^6)d&?P8sz~~Z= z58gw3N}bJpce1*OxC6EBU_q4Hd#P3KYq@OqD7|mad-PeMs-{qORxGutud0Iors$*i zn`7mNzUn)zIJTd2jN{Pz(_YJC(%tmEmfIg_>=&5S4?UH_JK%VUqeA-;C%1ubO@Ogn z+fARN*&C+yGp__0b(&b3ctqxC>hCe;s2X3ts@L=V26diI zWVsiN2Q2GYJ{sSsXj^dXEs=kx@bCz7h|AS(|5lSLLtTC~=UY3*KOMxcvi!{WQb7|} z)`ZU##Bjd9yV1$6Mm%o3a#@AQcz4-L$MKcu{l5EkbAN<%>^e22AJ@R?G_uflimor= zDtcBh2VFAXB|_fkf>?Py#l~wsSboL4^PLbOg>$@Xs>GZ0>$qQD51Ucn{BmWM#zInN zYWY}W*3O8h{dZ)hRvoO)v>8@I*=;#J+Y+NDj}Y(Ru(2se>lRqU_7&|vPq zBSV^un2vdOl;?QN*-HhtC-|)OU4H0Uo2s{1-O>dpr%@~B<6mV5ho=fYl}83Y1GQEO8}ipIV-Qt9I9k4uTId;?oeTDPt=43YAU zOnUiw?V~+hU)1?WODwr%FSRM`A3V}v1b5ZCn6iT7hst}u{i|ON_uNxE)b|b@Z0|>Z zm2+a=FvQ> z(7(j?*7_$$UtPmX9Vyn$jZIcP6MmDBUY+yky<67X5B&#(UB#|_wBYk(bkr+ISLv6h z%uOWacTOLFA$)Kv{#=4|l$B!J3C+;7mVCu4QTL|(Y0s_+dc@>qsI1qI%^MswUkEl3 zbT_Ym2fw@_6)wNrlMK@x+h6hsTcio^U>glOyXs);={F zERod_Slya_vQY|V=U8$Ze3?izX+wP)bH*IX23tU>*ZUY?Em*JIrRl*H82GOyyk zp6)W)CFgbZRhpzr^vLq~?Gndrg~yhq;mh!`F5(M?3k~A0))%Re_kS{JR*y6!xF6r^ z(-^-NzAxY@X`i02u-H?jZ03IN(s$=(o^_{dA5M zY%{}Rw(~VBG9?JEZU|1_L8QcttC1l1G6&p1NDiWB5L-b22k7|U6OU0tVl;q^cr_eB z6G1?!f%9)57eNh!*92GwOm(mw11kEF{ljTc#0CXkY%wYOLE!%b!89~6YB(eYfyROp zG_WVoz=KN|nwkhS4y8uG{aLi7Sn_X@v0s*0iYCDs;q3uvY_@nqI(b;+c5R!?lSIdJm;Um({yGgQXNO*C5U_T0OP7FQ)|SE? z5sT%bZ5v(kpWS+>;JDtnRZYQBiS&gwK0wO;ksT5-+0^(XmE%c7>|fI6W*e$q16o%p zw2%72v)yH4>ksF|(W@-)T;3R8bffO+h3glowWUWkHZ`p)_d6Y0Ug*Z%ar)$zy_>ny zkK%5bi4sMZqxUZtF}%KSvr~gy4B@UR=Q5rtyhGbvg7Ue2@4s4^HViPn=8|uGzxL^f z&5_z2)-f7H@@fC&w_g=IK0Mg(3*U0P<5Xeq%fS} z_XXBXdm|{?G_T|0{8KWIrD_wW9#WsZy(2Xd1QvM__xW4MIj8LI{kF$-DgCS4B+tA& z>s)z^MUM6acJUtswrtorPHq>W5UvIvf%FMDi zF~fK%ky}q*)Sym&z8t4GcW9TQZjY{C(Sp$g=1xQV`7FaeTb|i{i0rYChrRgM$V?h?ncO*}`eM%|k0Ve?<^-$}+>qhch#wA727wiNYA8zy|(lb5lc zR$(i7X6l1qyxU`*DM#xl`SKe+su}9shk2s~69>4Y!43fPB|kwjKb!O@JZ_EBXj#KE zs@;n6SPlp}h|la-c_oGUh6r?> zRc4rG7d=9+!s=0Gf|ngl5XGD>{isUu`-+mTKJa9Uld7Gl(;8uZaxx-3Q+3xX&x5kO zNk>!%&-Z=#>!tplP*R=3(2b3=ybEa~`OZWM8aZ=GMMd*>6uDxsKOab(svMy46}TJFE_WEr{Z$ zWXzj)xsg%E*=1kUiXV0FI_341J62`3Of!0CXYUFFIUA{!_o55OV-o|{HpRmqI3BqC zqWGonn}E4%DW|2ac2|WSNGLr0sdn>-@Rm#O0!NRmKHH?M8D%56*7Amy=b9_~PtPA} z{~Su4kWZFUFgoV+=ylY?xO)}-kIu_T#;o4$eaNw+XxFR$n@yURzV7~t9JsNgUD!xO zMQ?hqgz-+vJ+F7*XW%uu+llwaUnv!T+4y4hkE5G!f81*?9r&$sR>WaJO?jIX?)G{d znX8#g&hX2{IF1iOV?w19FacY8S#C*bQ}O#Q2{zRAtM4TuhSn87YH)p{Q*umu_oU9@ z;k9uJ7U7KZACp59zITwuZn)i?57oD8JVTm1Xw%nfM%TVZ*gd>DhuRyJ8wS64%=lno zc5>G01GPvq{bM?kMzffxS)=-NRi8t*4qn=2Nd5NWL8;Km3r99>e82Il7P(1r6wOtV zUftliD#I)rCgan%EY!ukg(A^sp#P#yaJvD1b*8rh#?{e$*Od#Govx|PcO3A2i9yar z-9R=LoU&})Il&*_chWR=CF840cQbjnVyv9Z=Ltg_Cmz51x8K5ar{WyVGahxcpe?I2Qm``G@f)i3$&Z7#n!ZH~ixS+-+sJmO6nN&w&$TqZN8WqmbGtQY^Vsw; z!u!vp$0(kRqe^EHsga~i)i8}C2dZ{I&NGfQIr#9%!XX6G`T6z*QFLA6nuPAkmPFOU z!{xgB=0YzgMpqqvu*Wo3wz0?Lw(z#&Nu#TslMV~mPM@Xte>^7BG}FConm;iWZUxH{ zQ5hdG-Y9cp`pUagy@9c_n){NJ@5-;+zW3W;s8#E?Dfv5wU-_(FWz2Nc;+=Gq5uHEu zpL)1fxvu`GRWkkFsIsXI<*K3ZWqAiz`v_$;cwm|1%gw}>xl~1q59GZ!lHQ}XPe!Q^ z6*)_PasBLsd3^;?b?&ig7{gUc~sZycq9(;43co&z(BVgsjB_j(t8a!8xR&ks#9=nUyU5_P}l_btfXsy|RCVU^}F`_3Fd( z4uRF7X8 z_$F8R+KEpcz3ol(=;skU$L^2?xrpfeM)CK{Loe;n9eNsFedI5rRoa5F_!ZJZVjCrs z%Eia?j!rb3*WnzMm5B>|Ap2s(3Xx;1Sag8@@%qM_wWU*Sa0RJYItv$ zZqMMYw!E-UZMe5%1G*=vBdNT)>&kUJW4thr1Uhn6Zn-wv?78`?3m;}E58ir9xBMgLK_5DWWU%DGY<_=z>Q=FuuTAuzukQV z_g{laL_alfheX{QTz6JS;W2;P0Wj0xf9$~DTKI2`VeTN58LgQVt9BatYPL|+mCTr2%;i^5FM|53pIDA6wsqi|R?0x%skPD2fk z1$z+;UJZ+cWJIfJqW+)iIDiyP1(&l_!L>0}MyM*8;u9S1OHw7Of-}uva;QJJ038sm z8cruu{2>syi~RS_LKgmi(^)jw3xZ7-IGE5>(*)aF3=XNLiNrEHjmJU*@V8<8pBt19 z*mg57p8q~v?569O-heIq@oZ-i zi`~mHkA{{Mza%UZ4@iPzsu`iUIKaxx7MSW~gF$#q^{~M-0F0@YpD-pV%Y!em1NZh3 zIA-73%yYTF55;c`G(i)Ks$NR1AT*hJ{`QBjZyvms5F0XDA%=^k^^5{M38+*4rYeGNyz5Ie%U)SS+~fF4az?MS*se9&13UY z5D+AN42g6SGtZ~)U|?hER^r1MB_m|2oNkCkb|#ZG?yX(=z_gb0QeFEk7Ql2 zXTG3N;6T!q><~B> zB)Xs_1*rxF8U*lUm055WNA_BXF9rn`clgf|SQJ6*!lZ>@ENmtW9HrSYQw!{RTxyY|4f-voxCjOxbSsW(F2kEM=pS zK#zY{_EKE+Q`r~{yRy+>=$4d?)&w~~kjBLUu~}sdo&bdZ2T%CF!(s7ZJvBj&5eyjH z6N3ZaqQDm+8esJYgRB9DO%n-*7o!P=6vQOJFX2IrCJwKL0;T|AXy)> za4299c#vsj)w4K4w2QpaNYFAC18Ct)-b^kmToe)sLZKx>W(Agjhir$b4pzsQWjG7Y zV#!|1WDEjcED(^rj3y8OgvkNUg0rYta4ZT3gl0kTC`g7yTBg!jWhM?>0}o;ZkgCN2 zZmcp}EmK)6Ud-ozwy@t8QD)fsf11t)_6A$bjDdw2x*-XFvaqFa{ilWDz-KDZEr-SF zjQeF_cmjy%z&#YGJ9sQKeL?IA*@PzZ3C0JDAfO4LmVkz)F9riX3@n~QqZ~{ogV}OA`&7;sv;ze1QAWd*h zL<0?S^#`Z9r5wPzzZCsjrvs2AJBLeyAL z`?CcI6VAd%A+gZdEfOy#BKdLG$;&TXdZ43=JLZ znJxi^!Tjr@gJlxZbN85vb5-6F$8FY{>!HZ=pq)*d;&)TSt0uq3(nazmLMQ@ z0M-MJxxkncFc2K53M>P_34o=AfI{GLOehwL5ilU80Mg)?zJwV&;J_0Lu5y8N1|C9z zjq-EAaE*0!L znd=+|n64%Z3#x;&^n-=U|Jh{NqxXO2cFgTP99$e(aSHMes|eT;v$91$-45zEw}S?s zaxR&S1`r`x5SuofX; z(4j~N3S%@u=&A`aD`23R27tqYPqdkC6Rf5X9<*{TdLAY<99oC);LMt}CPNr3t}Ob+ z7Jy-ciNe%7vjtX*OnxYErw~{-i#h8F*&n+aSY-&xYLdNfaTqbstYj~GszN`A0A(BEbQ3b@msvjKe14OR{iN&nYRI6D>iCLD4f%qJdfo`7Ft zdtx=1{*DC!qYR>UpjdFH82XwVxKQR&4B~WPYan*V1Rn7EOg`-RSSAhztQDa5fEx~u0hquUvoM*pOs)NAqk{b5l2I+*t{{L34OUK; z!(F`d!nP4--fCI23o!YB!I+cC{s9cIwE^a02<`~mk!VJtA=FR`bo(1@%-IeCeq{=N z-QO@aa{AZ1z(0C_48m4enp&8`I5;?9=HNfrkJmi;7Dh%p>>O-OEv!sH1q{ZM0e#@c ziGaaEz@2Q6fk3#qdm#9p!8lqj$n27eWS9wcJ|oLoV9H7Ena zuy9(0yHUJtY(W{|bHoLOZh>eaoI+ocu?Z+|0_9uu2uG;Q#EA(ovRT9#4J2CHfwCmP z`HRZ1TjawjP6@Vw#u&8AsYjxlII?It#r?>p7K?B{YB19d0DsP8TDSuwrz|MnB+^XG z7V-N?6z4@+E>2&f@fHAA1LLU(vxAXfG?*WZ3=4)KU=A=dm?8LU2A~w!7^oq`d|;sf ziw2%cSpJ}9sWuE24san#7nos+WVqrlF7dP-WS@>>?|-8X{Z$Y1XSM>h&uWF$D(jsN z3;Kzv3ZwpNziHPk@t-w_ZtkkBPXwEG!3==>!Ay=JfGZiuM}pCR;;FLB;73W3{8@v5 zBqSZQnYV$(Z~6sAK1EIW?2^&;9uE{XF2`2ZPlG|9Az9 zGl?Sm!C=iur2P7MZB#ehyhQTa3*8VIza40U~aKc~*$uRCk9N;UN zKjw??tiPORIhQav-<{?9SssFLf4qPh!8oBG4(5}SlZ%U&n+yE#@$hi-^7HZYL%#y> z<;w&F1mXPr%Y>H+E*Ann0?Ss22n&foWrztx4ybs!xp{>I_yr)0|L*5U9ZZCubBOaD z7l$m2Q-p&{gyYA3*gBvD9ple3E}7-}Ez3A}#*Igri>kBE$lj!D?J|G>dRhZED%Gcu2#IGL4w z?tFehVbO()#pTzoS5)4ps=j&m-u;HgrskH`&L>^nJx_a|J%9CjX!y;@+tIOiA7;SU zAM>9+FMNUe#R21Db?ax({?;!M&@WDIZZ2*Hn0gqvqQidWRYo{t!|QWm|J zf0bcs-qm^mISq&RV&1gJ@YV8|R~tS+U1Rp_pLHz$f7G*|9sAX<=P*Go4lsCJBCyS{ z_f4^9lV4Wk&V0)!$h^G1AiqAg=52w$O-I7aahZw*M^{uLc|{velUUB*K&oCq3h;F~ z&Ft!LjOB5r(oAFQTT0s;dWk7q2e#&pl(g5am*SeVq0gj*C3P#Ee9Kv$K?#xwblGk9 zg)6;{)b^>xxxd5SRlYxI=+4FqEoanEY^dFDlwe{S(_4CLN@s7f(qBPb_1rt1T?EYs zQ{O2SM4;;B)@6z&QYOlLx4Cb=-5=v!w7fc&e@aDt_gjY_Fy-XCMee-cE-IXZ+YRjPnX_HVNmII9S5pa&tTq_PEfwh9Ddt%yJ8X z#qSYx*uRk%=JmD!A7{|KU=~A_ao4r2&Yw8yU=+h3d?T9;NVJG|tP&DG<3W^YS$lYP z)rP!ty;aA)HVmdF&jlmDc#T}k>qF~Sx4AhqbqU2~TYiz8IAR^YzhZ zr&i-uJkzZzQCZiFY74S&%BxVkaUoh?B>D73w@GOse!PI`e+ zf6{0f4s&$!Id?(2<>Jtxi9US-g~zYcpAiz2kB}R^)03L-Fz6+cd?3f?o=8sQ1-FQ% z-Pfz()*CKLX!qChS!TkX3+V-i7f#j>UuYh5ymm#+V6$a+q3z8I5i_@UX5@u0JI8$k~$8AUF)ev6}}dBTdD82oCixN{tDbOdH{0ssB>&1(_?1WCeRZSs?XxSdwjM8N?0bCNWl%7C@0*2H z-(Ls1AvyRWgzfDgCWIj(hE`$LTzj<7Qj^C2w!$qbH1*IZZ(#9IguCq<*P#tWd4@uv z(v*?~%1F9e++pWBONn+~esSs1#&028cVnJNY|l@(ety5^Sby#iCP}zpXUc3T# z>hrStWmmVZuP2P;)xhWFD{pL~#e8uo_I!1)l^WHs?OMg4=)v%yW!nYhmOsBz>hQow zd)y~0tt-Xpa!gZI#n--&*|PpYc~N=_s)4jsUndP|(H?Zap+_T1k(6`w#?aMIkk1Scz}C@UmQVTUB)wlw*-|0UKklX}Dtzk9$?y`( zuhP_0w+rRRkJgn9J-@29YK1x1m}jIY#lZshHT+T*fBh!Hypr_(~b&rsBRndfm=>hIN!3F{9RN^B=eChJLYx=Zhx ze?~Ly5pQmmepmB$;;W6>olhCOS}KE3*K~!Yd6|-XBWQrxh6?Ko~Ls7ZRbVHVZ2uqUxCf|r)x=XFTJ^aAoUti?r0XVWz@tWGhqdnZ&#YsS;Cm}gXKq$=Fc}6CHNh!5feX#%6N50 zlERr2@=nX?je*47guX6$pX!a}X(SW(tw>z*Yyq_{iR+!xhpW%7!G`CsI6LV}!d6L6 z1DO(CTk?dE`4(wAy>l)#;81m(Cupf1oh8$KMY)~h8WYbu@wN%sY%{0Ys|mgjfVko@%+*(vK6dtu%C^~2&( zV;;rZC!d{O$W5>pUjh5#l!xQgM|{c6)B@pQJiRgS^#$Kyu7rd!hl}G^(ymq8uNfxD zZP??1OSur16W*{LH;N?a_;Y3$-AzAT^yEg*nX8f2s^`(h3#PBvj5{a!rWq{6#s>MB zS0+4ea6$TVqG7r!Cf23y%C3)Bal7ps_C52e@Jh>zczTD}&cG5W(XC&eSk9nP$#Xg9 zrhSj9wXR>5%rO|_6s3%&mCTmBib&Bl#b3zPIKDM5mV5y>5wzOXNsriP(-%>46`{<* zS4ay)+|ic0AeP53-iYVoy=dU+=w@-_!skY(%Y3)PTts$nEu%&e&MNZb{=zE4FGPUY5j<8@Yn}G+MY$P8so}tzChH1;Yvr2B7moNn?){SB$aS4# zIyH4s(DF=9ZU*Nzv4jXxH9hfb)|%bd&+hFrrcYzx)(WLTlrVGnQXeJOby(zVOL$z z8Ospb$;KD~$+EsP+cTqArI?y=VWp@?>#o#cgO&F;3Rzr=-d2x!CcA&rt@mbFFVkgS zE3YTVpOls0dVcBb+B=fhp9MZJG)Yoir-`4ozb+T0xWHHH(YI_r7gn~h#(YRRuGCR& z9{o^lgB*3;q}|o4VKcefZxf#)uj(Ut%!X0n1pHW&L*s%Bitr!`v$Il1+KO zD#v0du;84*#1?ClUIIg*5>JiN8@ah<$0-T9vY_lEYpd_(gl&^9>_5^~sWpGuk;|U$ z_O?VU=(N=G{ak#q*N0x#$tdqH6!)4N^C-Ee9B0uK_$5&l6a6uvT6tG>hr;vBLx`Nc z6XaDQYCDG{uyV!f!Rcd0E^;CKLngr=nn%jGr3Ay0Iz7wKo?JTcM^0<+&eaXipHrTY zyn6bIU|My)TMNC8Yuw{p|LH5m(bzn(6CqjJ0XbMT8Aiy;Qx5)Uc489RI`#--A?z2-?oXw(M>iJ?&-p;OoF`N3x%m zcMVxz-dcnezqUhT6TeLS&GUh0KURI`Szod3*6xa7n;_!GPlSZfdO1RI{MDX+{)&qcXM zN*;-hE9!qX@Q(ax)2<2agvOxUs;{RELhs%@f51V@yZ400`Hx8}bAvVpO(Uhx^Hmqx z(9STvgt>Rb@xR5s*uodme&Jb~Ev*LG%O@Qhq-?R*i+10qvw&C~U#T_hOmI9t`1X5x zXU%E}jey(v>Jjx>jtXZi3*;wjhFdynJp#I#9v{3+xB7}ysWysL2_Saj-rl@=0-w6q zPgg6cd(X9afd_&z`&^z?w2B;%@3i34j;I{+RP^-GZI8MS)3$>jnRxri)$(|;X;@RO z`m=`B-WBbIE`kI^ScA(3!(o})-4$z2@=HxARG7%$K{~@OjC)uFM6Zy|N&4_nWX$d3 z0r}J?wPdSjG}mP1q_RexLEoOptC!SB78QElHoDq9!6$v{#dS42G^9(@!kXm7PJn9w z4>%?reHrqlv=Vwdtv|y_Dnud9EHHY5qg46;XWrV#S@|J(t}U68CFag`s`YqXZ6~1t z6yi)?kpvFq5Iybuz|V%ZJ2U6(zS)iLI8h6}{0z+s2}K7QSAB`N zwAI1X`ki}(&^;-czh-Z5m#rV#n0s0Hc=G$~C-FWecu*8Am4~zs!}0jnWo9yFtpf5No#ocjYto-4-rjFCBte|ExPMeDJwy3H%B@6` zB&FRJ4&*^8PE(D}43YRtLVQ~t?W^$T*4V)6RFb>hpKu8hCS1ynzCdcpWEEykHUzvX z%+DWi)bz5W-8pK!B8$JBrv1gGr0J%PNQ1$fi{cXEQz~kXTQu-ZX~Nt>dKm@02HG|| zvn$Pb>}`Y<#;sJ|3Fu}dwwV;sUiVM9n5We6ZPylY&5Y843Cpe8#NE)Wka(KIdD->Y zzK?G0+m>H6nYzC%F63>gPTq^EFSD3VjRPuA3zfE{eBH5Dzl>b*XjV42pNAllW}Yup zeE#S&sWX;GBF5?^l+BE6Hd(+Fx6W~vTVIcGv}LF$%E`&}7A8<l6x9k~j{w=ISa9 z>5!;RRi$DRn(qu3Q2Xn@bQv7ljO(uzn084#K=5`-#*bOm*?-dX{Zu6LP|{Gr2FV+R zMeaBiR+w2gYIw{trsbm#?3kl-2xY&jX~IX*XuZ=HAD&gCw-lYpD(4FfQudb%!&=W1 zrdp56*zBAya9-IMI%6AjoukEdV-mCEAGlENrRiLd zXfBaOuHloIv^wmmldK!q+iNp1qZ^c~ejelEAbB<+z3!sn@&To0ohLUaNg>ZoYz}F> zz_)Fjt*w9lNfaX!z;`F+RxwB2_S5gAYbrCPmBYO?&UiFBubA`AFKg#oH|^`>JDidj zG2gaX`=|=Z$t!&JLin+ zB^7%lXI*aQwBXa~_TG%QtqApeJ|gAi`{}}Dh%NX2rV573dsyu;-Qu-Zld@b??8Kbr zWHNVaZ^hAUrAw?4j_bIxYnR{d?!Tcomy>_Ve`kQ*jf(HDbGQ;d_w?cN3Yt5H9Pb53 zDm^!i9;tY}uf$ggFVS2kFy*g&;?bql74}sImLC@`&8?rW?%1;0Zb(WnDf?d45n5W5-rTb- ztL4@yHg1-ztBG6wti`djnDXVEcjp}b#YyK=-2TbkCpJ{~+H`8vHF=Dd`8b3f=j(ED zzI)^NEv|&Vp6x}(8yH@#Iu*UG^l_*AX9-g2lP;I#UsOpcD)dxW`;#&v({71Y`WwjAG-6R(jxN7axLiMRC#PUQ4WXqnu8Tjm743^$r2F=>~EHfXRr z{@CY`jQgR+r%q zZ$5M7R%~hUj)*gup7x|=_+ljF9!NB;8rf^S6Iu5*$K{-{g~D3%i~Hbf!XB)~T=sMF zxSFhLLDCr%ZqKOW&Z`@HioNA*I4Bf##L5nmvt>Zef8 zOR_9|rM$X=?<=)O>o`#cY6ucAy8BE;wT7*K^?ILfbGf;Evy{rd1M_054F@^b=+!FO ziO6}y-AfDHy3!Su*@lmn@=>Ol2AM=;3JFDhJL-Q|z#xtq^ZK$W3@^?-RuOspsT?ByDLBtEk?3dRgw)1xsxS8_Q z5mR%KDmME)x1?4^ij2MJIoE$;f>-%T3Q2)mCZ}8T#V{$FFmiRL5V`b#6yJIqUAp!1 z6Yr{}+pt@C?$MN;U-}?I>|(;)18?wGc5V<~ZyEo#x?{{i`g}Z2=vFrE=v9uKoN&%_ z{(2F5^JXz`ayqM@SuRi2N!n#cTPdVN!1(8Uh>Cq<=UHL5mq z(pd5Rw>noHYrJ$HegB5)3o%!++NxdEB|)_|-7l(yYKwgtCbV-lx)<}^O>`ty?uZbAU_8WRDm}{#OaY?zg@#-BHvPueP zdXq;vJVRGl?4*D^y=x|rp-qBoOmFSH@L-Ggm(#^gf+7pfRRiSEo7R4$&n+^4&H1U; z?_B56>JZ}bMj>Lm%LAd3robq9|Fq}}8LQVR5*lfNb&eJEuB0yf@!a^biCKj)2l`tj z`8aKdUv7N<)uJ^UV#wli_GbX760&QNWbi&;^-8Me!F%Zy0%9m!dr z>M|)05uwcGFPb*sDXR zWsO0Wcx_INFD}lvPTDtj7`0LE-&1)CbKc}Yc*A&*YKVhbY%FV9aZG_Ol6XM0z$}#R z@_36>_}c{c_HtxJ!G&UU7A*YgAM19dnAyy=K3b@`hHaf%m`~R3+0dD=R_JWcTxU49ApBnS518}aTwUeh zH9bx0XzIK3$-_?xQC2<)RsIUkZwAG$HmoBZrE9utKfp!5uGpux1Dn+nh-g{gvTnbZ zr>XfWZ;_|J4^SYSC7_FQBHFGtum;# zfV-9{_r%8%r;;{JML3-Pgb2si)ytk|=(#m_=$7bT@K@cNeYo4|$O$+q$JN*2>Wej< zBPw@mT1bQ@G3&E_A$99^xy+_=HeJ@c-ms5{AQ(OAK_(WJCany8#F5Zfp`Q7*ZVim% zW#xv-zSF`|N!=PN<pMIyd`J_va+=9p z{pI8}Dv}l`ec-z95w60(LgBn`#XBxWnrX|zB8Fu&8XQw#IdiaeI(O9rHxnL$X}z_+2Ca>ZN6j-l}M0y&Uh4^Iic_d|83m3O#YO~0CKY3CU)$oVy|nOu!5MuumbEoIo`^A6=T}E9`#`7 ziPJ49QVD$^ogtt{;SbJ!AnLDs&_1`~JjJ4sp8B%rc1AYBpX#f`ra?Ho z*LJ&HvnlTsEL^wvZZhxMv*Y%#qNBIca|7=t>y2_1#;TYs%V{e&vAUuXZ>u1N9wNxe z6)IgQdccK{ngg%N_y%%ISoG0es;$%$KC3TMPWf*RkMfvOn|Jz-lw`QNUbzsa&MlQ3 zI8%N!A1OW&gb5Men=^zZdXB*LTO`^Pu9}?ie)!OwJ6T}NX}B+|iJ)5?{PB8xpu$4N zOdplU|3R#oAIjNnk{}lCC=wD{ldH^c?>S8Ysfn|$;*^A`??K0dJJYHfwVj5}P6Vzd z-qBh4B=O3?reJ+RYh(R^G#FpbQ|`{{Q9F-!`cA@GCq^h)x)+mj-si)V&DJ(^lykIc zs8*f6Co|U}KM|fkeNps^MtaxlGUHYoe)-%?tJIn+dfna|c@8}J$kBW;$SC04^V1)` z_17wHSg^a77%y8dzJeCGHK!(`II+CXdR~qssLz+C-4&4kKBlX+CiMtc^Fo*`-TBSyF*Yuvtv8=|7}YJTqvxuCM@w&2b+Qg;w~lXm8r|6`8EtWqD^A$4BhZmt z3qR;R6Tc%N@dTG{hqSe8qQ3C@;?~m-ALI!7XYVZ{o~7sbBnGY54m;+N<($J&C-<~7 zXFLw|+0mwP*JOF+t7csd+ddpu&UdAWvnG%Hv8(U4rQjQ!HV`#wz8o!%PsAelo26p= z!Y_n)k^0*89AbLfZXwDSysrGUp{%M_?O_3?=>?|~`T!o^#&9XKXfm31TE9)9g+beglUBA7ZMdZK zhopK)^3OW9C0P!OZ0&x;73TA_^QKDEwzixUeA)K*WqrqC@ONj+np(a3ijRlf8gy~0 zLgt7H1zGwzR{2W}OSWb2cbQS+t?}YRv11V;Q1+FH28%UM=pj;}Gk~wlSH_4efGIQiAM^u_IbDR5|D>qAu9GhE=9HYf-xy#i-{eJrs_SyFNJkR@i zz2A>T6my-K@vU}mRL4^Y&z9vVzX7xwLfzF;9T7F>x^{b3PQhc3O!mVbOcLbH zC^fBg`dza@y47{RmzTkG?czB){)twdf$<^KQaj~ z)~UCksqFCoH1vDR{QG32X)DxR_{Qjt!8>~KlgT(-9oSO~o9MqV3E>i|1RwMf+1p)S z+dze%QlsZiV|M{!WEu{l>wX3$RvwTAbX~*M1h^zaSDMej#%WI+8Ap4F#|^v6Q|wGyFr0-Ue3FvGHVih4{~J;q`BqYFk}`L!_M1eeu$Mh)7ui|w=I z5O>b&W`ZXg#U9$XtM>Rz8(bbasq_{x()O%CfeL~dc%a(9u+eNWK1~XS$T-6wxm~2o5yk3dydQ(>ZT=W(|*wG)- zYqL!D7=NK)-?0uiytO%x4!6?H<^tTAm_89yWl0tmOA@@udw6FC^WK;oh$v&du~#B1`}zxv!|&Y#KDTO2?8`rBJIj7 zeE?nz)Ifq6vSZC^sVe*RfDgg}duC9rBT&z#atzSN(R*6~c@j9|FF zT(Ol$eVkFkJF+i8!j#YEI^$$J&mEl~8=ac72{t<%;7TBoa|xn^u;J{YXWP0AuUJF{ zb6yOd+y0`a$P}V;r${c@whMp_uYNID68WQ|B-cyU<)Nu^Ae+qgOgUAc5{-g+xQ#Hq zTzK95U!+=BfzQ71kdG~X{20Xa^1n0~1 z>th_S6dk6r2qQ6*)_|a1N4;OUGs)T zfNdoPyuY2=>cHr7lsm*#E(7bQ1Oe#--YRpntq;I&%HkQyJ8U zEOD-$7_pNS{nsIBycN<|3|4dM3X%bc!|KB?zkDM*@ZCtKt}ACXTeTbXFj1dYv9fo} zyD&riVPB{m&%{7Xr1fkQj)znnC?`J!%@+Xg&?Tln+81UfT75IviNMH-Yat;2YgeOfQC_dn6(Sm&5#a&@LH$!Q%S%))ogs^y#b7AC;$pM`|$nr)eX%vFM^q zaxodS#3k5N|CT4EUsMihtkrG3f%;JEbOhQiGCyJg7PI3I*TYGitqu zUN)4(KC$-Dt^3Xq1|K&x;RQT;C0Xc%)kQ$m@9CS26yisoe=!l1_|OW0=UW&bzXp|(#^b>I43 zgO708t#sC_^<-c~P7vwR8V0N~392PBG_0EZyg__L{U{kkJb&SHL=(@2&{h@M)%YWy@sp z2g~UsMG-xWV8b?$f+OHd4p6`S5F=yRxSr9WhtIGhhB9CzuNTME5+}T_P zSG41n9l{4BDkqO>(=1eUOwx4`L+;q^cB7!((=c~`33b-^G8pIKUH{fC$Q=+gX#=SH$ zq}ZR9TAJy6Y`vp$84&fTF z!Y^6nJ%;E(uxm}NHda_`)IPYoGO@54m*#01dPxhB_+-eTfXaStEG|Hdwuu-3dR2uR z){ETT#gJV$p2#p};d}I(kUfOWSmeNYJ(g5@a8smwO!Rz9D*h8|zCDeCL?QMaTP?b; zbp=n{8ZXODypO@g*x#E8&XuC9_0;wThu^*GnqLAICiE&_kvh0^qUI(F??{iGdybAv zhn>idba*}RfuCakvpZ4~j)gEyaU9ivM1E7&C7?EofqQI5jJj#@>TuC3U}8@SVku85 z%$>`ER{*U{4uhhV2giiVz_0GF61#SflY>uMM%+8XFNtVfauMAE5Sn` zyqPa<`_YYyH%%NTFYNs`7SblY=3{{qI@}l3Ylk@nua`3LDxqz+R0qfv!za6Qrjejc zhnb7r-sj`k98(l(zSCD52azIL44Enr@@fZa2X+l6HeNyo@s|{87uY>-`wF+Oc+F{a z>N?}B0^DgDy2rtvwCQk9itUap$4t)cZ(7h~n}*V`NppXT8iUO8_f&SEu?7E3Y53UR z=@(0#Ah|(VHFx7zG6@CWP}PEhovI%JTp+@>rJiaRdKl()W&GR^layOn?;}^+R!G3Z z^YJPU*dM9+kVO?H36!DQ-9#3aeM^Vyck%0;jIFqe55K;RS50^J7%8#?FbP-ko=*4u zq!r=sAqUZ$sq~_Iow9B{>AW38a4_N0{KH|L5ZN>di44tSHK+XNuQ3NFfvnH8fJ|T6p(&;b{J*nAGTm42kQ6#IcaRjI7LDocH7MaZI9TmczbHv~Ty3D!w3~Fc3}gANcP%CaHl~YORWU;j zPn|4cj&A>q`{9M&!wWA;J< zc|@H(n`62!h9I8QJ#RLXxS{jN>p5$}@viGZ`rZ2wd+&c2kLzq6%Yaz_2WT^$3ASRt z!yN|OQAQrlms^_v5BBae=Xhuqtafyb0xn%FX!L)a*r3Nz6*iyqD?`I;)Ahi0sX{~R ziUQ@d?m}10XQ)>oWOtwwmW<__@fMWR`q@-BzfhMV>|q&Qy@Md3BSsfM77;(2s^=FT zyE{@s<+9U0$fKu!q;6g7>Yr3H9w9hSep|=gx=sGn7BBb0{&Ce~g9`^^z}NvK6eOwZ z{PhXJc`4qTjm_l|UGQ}zxH1{Vj6)++yM%s6?QdGR9&i$`S6|pUhk}4{&UvG!*Dl|l z+yUCA<^=N4flM|{>XF){GNJ!~JmI4LCaHe}0TL`DI-BE0qahU>AY5U@?7?9{193rW z{W?CtbZ}=F?3lefn`c3Opp4St(%jVFouM0l*gF`;MD5F`bpcJEpTYSrFlB zcLOpCn+K`i*`VFsIskjC=${QH`|zS9naJp=W&XmdG_I!i202!7_1E@ZW+2f713OyJ zBn>3i-H_iD$|v$erydr%r*{(UFig3Cj&|1or z!nLjw@E+6F^3HQ%`*i~9zGsVK(}x!kTDE@pzH5aUQ4Rj|u}tOk=)Htx3lTnF1x_4L#g^okG zYH$M?dM9ezpIUEQxV;XxcR1a}KdJU!2OxHB?)IRJ`%kL=2e7B2{s!PxjxX!Rgw-VL zv>|5&JJH`B`A$Yj&b+;zombG^U<{g^E%{h*E(%Lw+O$?aEqf)YU2vE16hVODjmTuU z{VjHhIErkm#{uW2wd~3lX{?f6d{l$Nd<|41ynBLr%@qhWknojz@@Fp5Vh8A3Ycjm^ zcWYwl&(&M0vpEWOvVB6tqdF~@`39|SWSiJ80916p!)8Trd2YRX_i_I8qUoohCMTF9-B^wpZivMDeeBCh+fW zg6R{zMbRs(9mrsBy0@LBE~GAtHNOAcQYSJTJeh~ zsFl~+pEp`1JWZ)%8;|!`?|6{rn#_yRw1X8bX3;&3v*75Illo6Xxsxi&W@#$=EZYuH zu6|ZzxS);lW21*&&*|FS+2vreGAgCP;KC9?`@%5HT8tmm2mEwVSnGN@jv?&;4hv9L zCg4Dxqx#7Y-Cjt5if#u)&t1X2dFW&`U|& zx(_k)O+i&&H$25}3o^YFy1g>)m_r<)OdE|GTYYghucTyJ@B_jc$UE|z<_|QL)CO#ZxZS>q2&=mJf5(3%UL*R$=)5aPR_t)82{9PsaWXuvuLx-XGxQp5@UR` zjrJ`aT*)vo3Yp>AVa(?4k7!B3;UMj2XhFD&9NfFS}XR5IdYa%rCTWY$^8+Ln?R*24Bwr zB0Y{9aJP#l1e(8+676W1EYDIeM*KMP>21INGAwIu&+Q`|djVo#V5)uK8$IQvv<9Oa z{@m;6k^NMWS!?y-%sh@aqFl9+=O0M20C|4c3IfDbSJ9s1`9aIZYpvO@A`RAFz>(SV z#rRF<=Ajh%{XS8c5VTWqXP2Wl;I0ZH9ukma8w2bRd>!#4wju;9II}d6Ep*x&AibhI z7RnpeY07-)*wyqxiXJx+b2BlaD^jPvx%maR2J=8!!?}C%8x$UlTR7Gyg~cNYV~~>r zqTdd7zFQa{SckHIEC1*fIl8OYd&wZ%Ugp-f75U0ew}D4Q-468_;9-8nV?O4v&28sT z)#S5EdNrE?GuyQ%MA4r4#8NUr%Cj}VMc5+pYN`WRTnYDaPj5g*r_Sf)`5O2bpN`xp zKRF>;+%&hW;DgOu96)iJ>-JC2ZXtS=;}Uos3%5dNAm-aJt=%1Rxj{RiwbICOZwl#v z?um{^OxR?97s-%MtSltuhBh3?3QvL>0$!yILp@*{<0aQ7Ih!J)0AxGy(k8Caor&Q; z$eh@Fh>??~=qQv46)_1T9cJ++_3y4W@7?%qGUeR=x$SnUWahUW%yw~rqD#>LjS|gW zb9=B2upAOK;XQ&lo#<)Xbha5BDzbhR9fKNbL1pLP-iq!XshgSP#$pR5GOdvEpcn9>BkHXlyrQ zh;T3HP`vO*&E)jo0=4U*I?BbpTlN`(#6I0QQ|aGeNmkN_o2=&tNr&pkw~<FE< z_Y9Joe6m6pq76e^GWvq1oO`Z&NqCFfT17c&;kDzIHmea(gX~D@ud_>4j^76&pE(<^ z1uAdAC*@`muA|=Z9rrGdACaStzG$bLegNKMocXqu;av1uyQFKv=Q~xtvw?~^N$a-D ztb75G^N7QnfymiwFH>&h0#G_zTZ-JMh2M4KRq(CCcpHG&%1zl6NzrCrN1HMcz^+&? zOlRz|7fM0@?2 zn`UC>1q=<<(bkw?_EV3S+wUqW@TH2rB|-p?1J7!w7Nuxb?)hMT{{$dZ@3aR$ z;j|I2&8^Op@y>6)6}{AOB!A&BWlB^Q`YQI}-BVJ6$z49x0`=X%W$~7v{uoWson0qULtu3YCeW=B(@?Rd0VDHM-qK z$f~=qs_#h%a8#LQ$_^I$gQ$(xH?k9fg5rZ(Gw2i|fW>hn^q37{FGCjWJg+>{G&rt5 zvboe+7Wm(4U}`t=QoVOZ^t_52?`B7kxx^O8Q-y!iB*V4&&MgPNGX00$8074`mCCaZ z8r7hNeFpLU(=gp8dWIRE$?yF7SvAdTDeFEuk^INjvhKDECTG--wZxfEMGJ1+06zm& zu)yz())cNzSGC9`FOz5U)xX9|zwBGtU1}^>5_JIAM3Q`<2+8lD> zWJy3$!!K>T4p16ap3>PCR>NQRx_;M(?bY(8^K>oGIgeY`c8?kFSbv|eEA?lSg9akA z;<17IqCSf@^0SF|Jch9D`nUBUN;GOHtkVUm2kzfYwV0o#)c+SvF!vX}!OXaN+}yBQ zj?7$A;ewM+%AAbFU!IKNuPg$OUxMSGT}?Ib31tEzN}PK;viu}D z3hJe=x*iENY}DQO<~#PU1|(BFmk(abU&fXU+P6;%qQF88F4aCfzd0lm+`}Q|$dx89 zH{}%)(>HnMuj%6sNIw0>sJu&K;)S>dc^sqCVAN=|xtxR^r9E*ZrvGf4ndW*CGaO+5 zWB7^M_=7v1mRd7G+8!s-#r@uzwzU^SbcTRY3#z0=vKH#pR)Fx6uK~n zBRFcv*xU8&`TETJ#MhlK%x`wI_~c#QGb*d~k?RwS4yzr17rr@DV4)8d)(QAL&~vrc zAIJIz>sLOHcrT@3$vQW}#Wh=FI*R@wV|MC*;|L27tR9Zft2?irX(Y&xy&vQwBbKc< zmFV~#Ff98@mrevt@Q#Q;h@US~sU8XaqMNZZ&~Ax{hNFy}$xGs}qAE%RN29-R>+fJE zr`C9RK|(1G+T|s4H01XKTOExsZ7m`fXRWOamp23rQxxZ?+<9HdroqHfWLyBR^o_oM z7w0=FLL`|YvZtbhgZPv$yc+)Zeq}2w9kZR}umN(IzeNMxtGPUZr6v9l3sS6Jtsay3}uyh3i?JVU=3NzvEamMN? z9nmc3rL-|to#%oiFrRhmR3)S+|H6v>_72ghL;c6Ms&k%~c803|7=q{lu!w?uC3t`7 zuw(In&L%{I{Wo+puq-15$On-v7jV!+H-!N=TQ6%BG{-Gciz|N4UOcp+d?IDknc-|pWJM}Ig>jC@^C)^#c;QLvsG>Ab1 zSjA9;^ALGtc8d#dhtoO8U z_8+?=+L%AKrrt>jsr1?}2GO#ug=~`hUV#6c6}MqOTpfQrcxq0u6r$1%f^FA+};48N<;EL8F~WM#sv z0$Eh~XD%>1UT|_Ps;0vG;C}SHe|tcgzpLLP7MTu5sI=;|S63sH?VLw!&3vOlJeOzO ztK+JtLw}>I=xO>=ol$qSg$Cn8cX8gBlJaVlwF{^%yqBWO;nqj07jsP6 zB#B37LyRTCKXHl7Ax5GM3ELvh44Z%cu2q;&y|wI@%oy85Mm!B{&?9!WBDH@6IOm%t zZ^*_ZiP?0!Rlr-n#V_0xy5RLl=XX=i>?KttygW24Se{ZDDokx7`F630FIsw zq!b?)U0Qzc)(1RRgLC-`Q~2-=)MMHExp%{dndv#gCv~=>4aUQoR~<59R}jUz*>{~F zGhFMd_^ofU!Paj>K&;3=^HO`pU=KZ^`p*KQy-dPWYOht((wC**jW($H#xC4=H5p^i zyWaZKMtP<~I^%34LqwQ{?+vzdd|l+O6GkrwS1X_7KtLUhZDHFB@#= zW%e#vnAVLK@H4Z0Uvmd8c3;_(|Dj{o1*{k%VIu6ODHLQi_acl-ctIa{UcUSsZu!0! zxADJN9=O?WBUf7S^1F|m;C*Yk9H}sddEpnNA#5i4+cg;m6taR#euZY=m(!e7`ZNP_P- zbuOEe+=&eB)%#iRvaF-QU030Gd9@bV$j;PkLj1RHI*p1e<-_ZkdvP&g;=iOh8x43L?cT?jkEKHD zCopNtEnjA8M`XW@tZS2!a|~HM#9_#60M&05cZ)ac0&9G}#`yus+B&>gn!WfQ<{cUu z+g8$Rmk)OaCRyCy)w1)-l)I=-@+$rxpvWpp(+hW8J6<@c5~>*&AZ*mqf5nrYckc3- zH>wx+10TrF5d`H3k>mgbt9hzSd=}bv>@L*rAy20r==Cq#x8Yw7LtqUuQhqJ<4;@Di zzN@-U89;tlJ^Y&>c=MkBB`ghXS7J8z+-&0S7gy5oJ+&Z?VXU&ya>0kIOyZ*&SDR9m ziTg{9lKcwkdEyUUhTX>fLJPpfS>JDgCnEN3QkZYBNX^KLRynb&e(nv-&zf73 zf9HJ{!pF63bsP57^#^i3=>qkCfXk{grE!H2!30su4*zpb*yHQAu~B+KWdDT8AG`K1 zk05fEt4FnG<-(|$C*`*qr*s>_rvp52f!<=#q=zreE=*|GGuIhen};~aLHMnmr5Zes z$o@Ahtqj3#xn-1-p}VThKfxn7t3#riqFFZX&PW$)IIYZU@=BGsQs7B#ft{S*9koz9 z7@@*KVuvr%K1 z-gfU{cjl9!+xY&euhvNRTV($EMtRm(1_B`M)C|x=)C-)N!_%RaNfTNIxNj*MTd-QB z)h68KIct&$0I$`X4)})Zag>#IyLU76DW8l>f!^59cGtWTE05$#Ui>eJXH z%Q#b;m@;QXQa4jl|Lt4DQH&ncF4JspN^%DGN_}s+N7Mp#!$buWX)f~e>u-i>wO524 zv(f*NO2aQylTSmHk+jZR)JXur%x}IKs}Lsp00E6!8awzyYmf&la$pbl?MS(l?`%#G zD$q| zII%8`f?V%)O}q301g>32wu!sa8i$$7M*0~nT)t#MXi$!ab&I9;GtGt0z;P8-GOexL z?4Ig;dwJhZXbegAy;o+1gP)QAO#whDpVnt{-!bHRW9Vf@6Ph$D+?2R#&=Io2>;FSF zv4XUFtLEW#-ijLMZ$VU6?`HP^WLNjKEZ?s3?tX?j#U3$gzp#}V1|@>)(XLF=7RF7X z!p|bR;~}su%S@r~nmpEZH%2PM(ZqD&e}YrvF>@^-*`i+{Y6l{OT=JH)|7`1fVb}u@ zg|9=U?UGNJyMLD-hs;u&3|>5B?|%Sp14Z#i>qsh;tI|_MNHo0{K_W>iu1n_~oMTpY z{3(F*&=Obx>MC!Yno z$@-frZ?l1}@os9&XJBKHdG>DEYt5SqriomXc{`%|(YKg+a-ISU_DzS+3X=LC-96?P zintko{o60{>UWAfA3Y~RLH}q!byLyqeE05rv*L@%4ZX8~Xy>*%dEAuoC?=eP@&DLR z&_c;gjGpHo#q03eNX4(P%P&+2UJA3pggU<}S@}z2ji`0?2<7~FDQ)1qh0Ai4p;RR@ zb^&h~GoQ)0 zxUFF>8HpG>g^-oM@(ux4I2#wu&N9QTZ3z;AvRx^&0?Q?CD&2Bnzs0O3ljos*6nu#x2r=-%-ygMSgC9(0(Jrpzrdlw%p`B=1GqlMlRtf@5YKmm+KpU!>z zWmU%qlX}&;$0`QHcZPKjvfk&gOdF|5I))xz;Wj_Qr#8rca* zu^|DMrG08}!KStFVji2dz^SDo0S zjGsf&YpdAesJf{%%HL0@qmAL{;^>(96kBJN(et7yYj#Mcr3Q$}YxHaa)N1|CP2Pg$ z){W*6(E7HK3Yadc4(t2pM7`!1RJTEvjh6BOnhH=eUurKAQX> z63j7eQ|c3VU}z?6vPYP&#6iw-gI$M`Bc654W z^R7+R98?K&Z1hWc6=&TnIA8&Lf`oM2yO)?)FYFp$l+&k#fvTVj+{F+TWy4CyfWD;8 z^6g>9i~lBe8k#`n6h5x~Ju><1>dZM?-5e=CXlJ~TSRoD>VxsL^?t4w&)weu~KeziZ zX;QwkK&j~DvJ+r(EiTRezhoiszLj>*LdMROSK@AQ{*@Tk87n0c`B7S)^dL2|ysi;UzqOHJ+ceQhGr{GM_yVt?Nr{Yyr&(RXm%7WQLGE&P1m ztEp$sha2Zqt5wXeK;Qd-WJHG^4G4RmOMEg3%WhypMcpy|w%hnZm<(#tEEJKRZC)t- z=m#v8hb=Aa3bBB2w|1Yfyb*46EW431{fwKIpUsG=K`E~ADJQMIkuq-vsF%z%-e?Ox zeX#{wTNXoF$mf`Tqh;;+aa!p5u%_GEvJzPpzcl)vi}>BG1DXIoe4L^3SDwrGqs?^r zMSoVm2)U0CMBj~csS87{2S1X!SmvwGp*V*PeW@NaqL*GHQc&#q&-zr0FV@9#03;I$ z!$@UGh%bX69QajJD+{A@cgdNRo$#g3@~jsuHDJNXVfB&WuiFK4DOMAQ-s>M=%T=GA z?@SiUek}Es(Vc7K`2`)B3_zz1T$mCpSLALz9@d=gtWlWDdEuT5E9H=qX>>{bVKV$r z%i(&Ln-cVI9aSY|T>|mj9{Z|Z7!j$Z6}2$-GhXbtHCMdbgAw^L}lXRm)Qd>Hu)AxM-`P^>B-eAd1ue2;iuRu03GmsAb?58#t-*N9B0v^Gv*IGAk`Sin#{*W|n0spAo)R|zFdo_b+~GIXA?eA%dQv|N z)L2pA^)=HYi%81!!Y8g)E~!efb|RK)$1oxhV#lHORw7LlSY=I^kxpEF{(#$sIgy3I zLV#Fxiz3sFX2ak~fK5eC!@2a_h`p!Ty&xyIq7ZWz1LplG4<>Qv315#dA0bhV=U%Z} zsHSf?jk8r$9sD<>h%dw#m*e63>S;IGIIDTk5B4mQhcZ=t+~=?s{iW{01ISrv4AHacF?!QT3o(aJZx%j z0E(xkCB3PWT|)BMi>Qtcz%p?wiiVei8Xv->8(v#WaFlI3*sE+4C8AF%)9h-G_Z`rx z{Y2BXtXYR^V>WruS+KMwDVd~UxtWhW{mYE@OBi?))KDcgNYy*PH{obKBK2d}hI2tN zW_Dglf694cCHaW#`G;O*tTb*{GE*3T1Hgi@@rbItNdVG1k?rK{+F{CWzjiotMXX$C z@BaW-b9s}n^d>e4yh{fBvvFM)%@$e@a7AWv?wkBnVj{9I=NN*A8MJ~M`2``+zOHI; zpIkU`OL`|E0eRK(_N&&xqq-Em6{2o7ixMyP0#w*-VbY`{rXWb2(<78$=r+1&YDDK5 zcj>#s;uz=x%FZu&O0CZM!bpVMJ*o#cmTK7L#V&&rJP)!)rbl13aSIt-@AVCn)4V`* ziO{trs9E@o2;Z;_gpPh~WG| zo|y|wFDPH(k|?P{)V{9>YiL(JxUV$KVd2l%!5d9#0)PqbBr;EQ3^X*eqN##O*Pmd! zina4NK%hwTIxobX?IeT2GV>*pDiO5n%gHNaUMQG~$sP5$WD7*nX31pUmzZ+{Y$MX0 zNavjDphpF==)bG@kqJMtK#iP{yG4vWHa>_$N^E_;g?_qY0f}*d-p(I#c6O|t;oVcQ zm>n{p3H+v7{W^4EN>>y6`YwsYz2&SrSr~C+WlH<6Kk9cZHNLz)Ur4+#KJF3uiX34d zVUNz7BiqMP_P)Ng1&`S9!TWcOwckf%inP>@T_kArtoLdSep1g9=+Ot?LQ?Epm3cyS z+bMYp5EmJirCi@N2n0YStmN4v zv#v~AC$|JA`;g(y^SxEwF=@*t^we8H!t?=v&D(l;rs0c7`t@#kyZPbonJ#5PxAX|M zJ*Xo2s;*Y1yX)E>SKItNh1tC%PIT%kI$DLq6+;51GDg^8{;K)Grk0VH-t?r=9?2%df|9!ey%0NUidkyI7*EV|%_8w)Dfq8Sl2V<~&{~=eKr%z~GxVk`Z2W4grX!8DiF1l^^jZInP}8Gn*D)bX zpea*wXDDFOt!3K2Ee);yb{0|783-_;90_(jRs~$5=tk*wj2oz5x_QKKC0lUi>y0T- z2@SzbI?un>DE3s*^|BI9tv2S+_Lwt}ao0P8sY>Y9Y`O~Cs3F5TUcZ0H5+bMCS0~Uy zCLhrfsTWB|xRvR;|4MN-eJ+S^Ue5S5{YFAC=(u4d?|f+&-JTlPj6CK@Ez{2TW74-J z$}}QO+5-e}5Tihqlc^f#%DvYY9^lD`HlsTn;}G~#tubZziBQuMLPYqGR<@#)mBxS8 ze?Ef|()XJu%>!JGxr_T8w4P8PmJ-pa+cjb@Tt$@WA+C&A3>coM9mf1BUKBK?O;QN$ zd(lTQ-K!9h7Y$i>RSCqgiaR&ZMTOI=%$6gudor6)DG8k=7Rm&7h7kSqU&boki{$hJ|Se5AumJtJD*7asq`CuN*EhC-iL+k0sCHQ`exGXxQ9ngxPi;xIc=^9{qVc6*`l^s*?~@K69DUThe2b@9yXB9477K5VYifyQ{yM7^9+H$nGk@Ed5E49)(H*MZ%*CHNA9KhIlI$e{z@v|P}D zFTm}YsYlw!I35FEBbm;dHZn_*H!r+0xG(`(`iGX?rTSeRJ#o#K4wxGb;x8cLuJvzeLe(WY5e1#=fHVA5qfLmV1kx0QBLC74fOtj zHUiQ2!=#I&cY#>DsA1L2m|1EXk~Y`QP7sTSL&+sdA#oGNbSb{*@Y-|K^Hml%s~ZtH zl?`3ju|Eh^o)ekBgmvdCWJ4DiXzS~}LrzgR$pLzE(|bz2z2l}P6)0ZIAf@9UqLtzve6uxB5`)_WbDOWVx^4Jq6x#CoKPOwY^P7~Zgks4Vm|H#F$Uh!UdH zSv%ngWK_pPh$A4BQB4IiLWAwAUiQl|<0ips9sa&EZ@??_rs=J)|Dztr5qQ^r ztpkv;#kreGP910E?MhmD(^$HbuRGUoWA@Q@h5!m&Q1UFLcz9+xQ!;I_kxiH#l;AQzLN%dBZ~oDe#ZaYhOS;OuzTI@{L`idNWcQYyinP4ih!^BmUcTs}-XyCiXno6wt{{YW(+=R{R0cJ8c zK9`N0ZO{L^^l!q!U2#@=?(9BJz0kKl?<;awrmVjSry1sISD8J;=kHGZ{hlnC!E=$! zXr3NsBxFBClPE}s)vI@QHot%M!>9fGbS+I;#F$E5pU20^oIFT5bnoryAyp-rnfwoc z;O29LJ2^B$xOdZRO4N2@b07aVQM_8-ey>tV8+r7mP21~K^U*+`>gp4>Ma8mpo(1v( zgY2O3x_s?Q3j>wK>|Wk6x+W7X`;1}F|0--~s?cSAY@|xhy{@ZF>M)Zb4l6O-x8o0` zY&74tKe?miBasTt^7f#24@GqdcHJ_(%Cl2(%|vuUU#cu4L!aOpQFmaHvO@IKfwd7W z!NB7;>J>d~tn=k#65*5s@Q_vZuqu}HM#*g*ZjDls*L6xVz-B6=vPWzYj(zpY3M!mO zv^Hr^yiMOU$Ne#BaiY~{ab7V{?oZHciRV*0cflpTXRoHWjNVi_$2X(8p}kksAkw3Q)HN$ z%^s+0zh9zwK+xIK-n>#QF51?_it++H3AZv)4rY>}Z3WC$cl2nyHclq9_v!FQH|!s# z5LvWm#`}z;>QEGQ6;6VIn~CH6$z9{$WFthMn%iOm8{Zda;dq7&W1ne6;R$8bPce>Q zj5)tbr={<4?Nysa4zyW;*~6H%x+_yG7&p?s7pR@klflJ-J+7U1`yXH^L-Q}}GUl5F z?4l%3Jiv<}ILGzq@fAOWsjzVdvq}tbz7mm>!9)EkpC?eFq-adAkvHX9bSWj&Zkvo0 z!AV<^Pnjk|;U%V6KR8%s+sSI&$GkCNO0X2!ZwK@atF8(Qt1f<(yB1hd$OynwT;uQX z8Me&h+FtGOl! zv18G=j(lpnq_7ljC!n%DD+L-T5c4^~8urAdF+kLewNo|mlKt~1Ovc}$Xsr^tbfHb` z)sqlC7tr7d-nQdBI#e{XtP z#>UA~haH1P&SX~|hmD@{$}i-~AIk^wP9jh$Fb-GzFoexTj=9w%gZFNnWs}_AU}d44 z(n@;1{*-VnRVX+LL`7vk?CS@K$Gm|<`5dvn4c(+~sTe_J?8OpTS>hF%&f$b>#@XO^ zz*?#aX|{akbDaVQSox1yx;c?@<*`m=3RuQX+tdl~a=oAK7+O`Pd$tFU;R^ zpT8yf1|0a;P&SmG)w3=t_2MI{ow;Nf@l3u+)zYgv>py%{4GWUG-k~>>`AeqJ_DlM{ zO;n}PPm8!e^TmFqukk@8oDtY05~@8B!gX*|_xjqQQV6^3n(b7Tfit=OdPGo(`jdTQ zZ}KIE-JYDs2QLFOH*PagH@wqFIlDQcb<)Af5#3Ev$fP+*p~4~5)KO-V+Yyq%Ys z#a_H&t2~*(+2(F-r-E@&By1%cut6UuBEHy%_8Iu2{{RS1ovqz!8blG!K$_U8^AUZ1 zy=&-8uh>7pw_gL5to7|i*Tur$a!a@s^D)q`_j6YqP913Gj~=ciUqkYPWQ>Fy09&6* zuFZ#L{pI7*x{r!quw3?DEYYI) zW3F9Z*)(7AF&F8dExR(1J;xNKjKeRsjGa}chvtJRB(ciplbV5)82a_~ud_Tw`w@I< z(>zdg?Iy!b@dAiTw2)2Zo-%Mj9e*D6^52U5CE{NM_^N#y#o8VIgQ-T?FHSMnaT19l++f>eNv-O32XCwDpM;;I|m! zySqC-nlh+J^fgmWvsM5FIK_7weU=?ZIj%<3o}|iLrHe}y44a1s(z^Q_FeShRc-C0U6sn01K#IOy+*V?luwQ}rtb>|h; zHL=O#-l)$G6FhP|b*!4#Lz-`?$IS@A``8>Gtzq0D3`aTaO?8(sn)6y`3p~ouNB#+nit^2Jt z?)+b;-U#BiirsU&A2DOpVDud;&6h@l=u%IG}z?wq>)H+BGL7K+e(WTwb-W>ld#knQa?K8Yo!gX8A|Cu8zXm?$^V%*7M#cnYSKj zeC|G{6;Yo(Ys*%a;=SXc)LhuBY2|HHH2BE~cqiVtTOCit*M1_J!b^3wf)BdNcx;}v z4xz8=dKBv%YWHxqLjX@x-nBe9*B1z8mSl&_KQKLWS5pw`K}Cu-ayu_7@(nz~!R8no zDZtOKN|yHj0RAQLDG{qE+IQiz_z_v!rmC8Cptg?TrJVKJLC609TD)_`K0J=W0?6T~ z2ZSB#iy4lE7+bI6bwSCyM^;q$gW+EX4Ic1|7!IX!f7Y%t82TnQc7U4X^}>_KtrNde@ow$HM;r5j6dFTMa@-*DN8BtXCwR z=LGfRACa#o2Zqh6%iFssZD#ec>3?EZaOP;@I0fu!AY(rDhjS?^Ks93GZK^t+)roN_~>R%Gw$agkWN^Rg0WrCIXurLC$F zeb8t!hTsx@wN6*y@_6Z8kcwl`EeFcPsm2Ges*flKXkqGeQ8b%VmOF{yim2{DEEgj@ zn(C!Zra08pb4;(i^mQURV2cJr#sY^?mN=`@2bKf;Km!MH>U&n~QEiDp&!-jPP1&D0IW=1&wSRj5qzbH8OH$ht~Vr>rabLyb4n=)U@`Ci0N1OE>ywZPJZ7`i9BpE7 z2*EXJRmMI{fzq&VsG~h~FCkJuByc$5o~m{>ao381IY>V;0q;|*f_9QK)`dH=okelG zc8nfL6>RCJBoXV5IHsQDeAuUsKKxg%b$9w zA~DP1a6g3Bv65&}mCR{ZgOE@4to8w07&$$wW@IM~%A9np>6LKlnvR*B#eGFNrpcE0AFg}FQMBTGP&HNsM={Tckp?}d7y#;JQ1Gs zedWsIj;6X`w7Jy=t~7$nyq-r)QU*J+cN#Fk4hoP?X{CtmT`|=i7VaU-9A|IVoDLT! zrg2Pg%$#vX8vq}>j%aUN3hPnK-N8GtQRJ1*4+f+s00tQT?Lg>D^exJyL8_ zAqqLHC={U+vRB_dPbBRtoh=sHE_x#HVBF3C4ZD`C!l;`d|hEAQV2d_nLx!aoUG_0 zq_eXB0H<9pcS$cpk~zS|e6JI6Gs@zXC^^mStlhlbk2@0QFLs(|(LWDAW1oZG8POvD z0EC7ad{5#?lQO)Ih}G~8K<~|aYw1@DqiGs!7;PTHU64fzfRUg709Gr-d=2q(*81fh z&idZ;yjYXx$;ksht$WvmHT!n5mK(^%=lPVk0Fru-YWX}ibzd~9oo=6UJPN7C>Ph_0 zw^mEJv>6|`x98HPy%nx&##+W!E;HuoBdF%?oq_8hU`R^{w4-RXu%Bqa|hG1H8H zJl74W==a)t5lP5bsKZ-Ut2~HQs&+M2Q^81sUvpGYgba;815psv_Y7N&p%q$ z&|$uw@^h(P36&2jxdDbcbgpVkE8j93YiqEOY})xaKb>9h=A9*_&DniIQs+7IB*;LjEU6m|xcZvqd|jb}j+HAK0tjNk79!^ewOjoRUejl;j+u1SuOe%wL+w0o3 zm3ow`e(Bk5r*f&;v+)z+m+X=8JHdLFi8Xx(L!VsmMUxqA=ZV3VIJ)4D`2JP$(8$13U`tbn9KL zHl}mjim7L0z%o2ejT7v6N}Q=2ALU)1pJ})tAgJoNt!Go3&7EpWF*J1RG6>+P>P2^Y zZI;#zw2{`bw7YUwcG5?^ch(RURLD{oRJnIK>P)?7WD5cS0FL$7+FFKHz&IR!HCo2s zAx6f>a4V^`w_%JZ13l{*)K5d6RXc^fxdnK@_N|DZC#WW+irw-)PPL?wV__kNc;Hkh z^BFl6gcx7CGxX-9^0^!mPrhqSA|hT@m=2tGsl1{_Z~@MFrqPpYRARIPVI);aAQ;FW zrF3lsrb0kgj;cuz3()lGQ!006GI|`;v0^>A2b|`yt|AMT7{^NMW`q>T1JbbWlX8{8 z&T;Kr?weYe%3TgV?LhmW;PPvgzFZ?Yz#R4VuHx}9j4{aSam8fmUKhUch3(~?fGZSZ z65L}dJCHr=I+Y_%9P-%7UiL>}@YmsWzll60b>iO;G`99O#I>{zFeSjxKF6mXmD(&i ztbbvX!WvT8+eskv?X$IZ9x_MQHSS&t(?+r3Js!>WN2XXt5&X6L;4V4*YsUP0;th8} z@v2++S5JBL(=OSV$GGD-;?tUnX#o+!NW9jw}I%vx=OA>S`nVgSe)u7=;j8sCY0KMt?0+_;`7)<|ujfp0uAgog3M$&I4tJKpwTz>KYK& zirwg<8(Wyj+Qm-h9;Xzg8M;Y3rXJdA&1ica?x7Wpgr0d9MDv}w9XnPsYL9ED%QP&O z?K0$U&PUK!H{r3WS=&5%#OXE$)ndM#xvZ^T?)vjsHnxhhjNdWVGm3%07UYFh7_^GWjre4JNf@YCVN zwUHOsOXteK67D%Q^j*9Q2`GaDJP*KE(PVi#t0g*-yYxQS4}+(d$5qWYzmepF;U0$! zE9BW)#jtixN#mc=vhMyF+TDo}?2(rwDP^yH+w%uD`wN?y0lLwkruiKvzExOsrB?vbR zDQ0bo=Yw%T;p=Wb@@T<7;$r&B_ ztofu?i;RQsT37JPYjrd-Ay!j@1!2lak0jvwSIo|nPjlv@8x-yw?f@Qwu@;HxttpY_8zhBbucmpDZHv9Ok`h zboNE`DM|Bj%8+@g&IV3$!?EvHUxV`ucH*hYxDqnH$2ICxi%P*8^(!+dRv$4r?^NB} zZ{8|B#Z4~d8;{IKaa3e>^9Fgy`~`Y2rdKtDW*Oa+o}DV8k+;8gBaBqdw5xo>t`2IO z1{@E${o!4-sjKQsZq~TQ`>HdR?gdnGeA9!GjP0uoSD-(Ls_g5%h6e0)u9Tg^DJOPT zlO+ioPZ+3F-~dSn+N5q5u;;ZjfX;9TU^~{SSgvKc0dL-81oPZe#sdO*JuyZbc+XMR zo)h=GfalQF2ej0cTMPq?^H$R)UzBmSsge7_Ncpcu%Bhvkaql1BLt0F#qiamo9&1cH0iY|e^xIwO4~UF50AHF6nt{{VH3W1#>q zT#?eQqn*Gm(d$&1*#>LI>|{SKJM&gIA79q9;v{lU9r>yEMW4QE`Hq;q4ju@=BdPk< z+zN5P=BmRH9PQ6FvjilvmB4KB52bv>>ZW|;o%Jq51bAPR?jt1D#1`2`?@-&vml(xv zz<`V&l!Kht6zVJPbLg2~D3{CIw>Uh5R!krRjPNsx&{zR%h3%4RLW3Cq6ONV7DzRn` z?)NfE4VfXoE^06lTad!E*)o7I1GPmY0LP92_3cSb2~@G17_68b38_H`!D3t>Ql1N%xF0Kxjv$qiJ_#U!+L^I=a>qTvt3(qn zTd%b>#?gWSB-W9WV{(m(ZSzVn#Nc`s?1b?+RE!YKt^+PV4+dI*R$(;U$m7 zH3iuotqRoeu)Ey+)6xF`W!-W;W(`wEmg7sebGV|9=4-9hbblUrM(J(md36mnR}yFM z$BvArjy&tZuU_p=7{bxRs8o)< z&J0CrILUI(C&!)>_>XOQX4Y?X?Jh#H^&r==SiJWdVlZ}*3gvN(eQUrxYw+s#!(Jzw z#5znb5kPmWV`{kT$o1>ZQt;=CHCgO7lQp_3oW@+`an`;I8HuZx*5sGH2eUqNHp(T0 zX{}<5ABk z$I&gZf)`0{6+!az^Aqn|HZ#fMc-?hGC|qt5G2|R@E1rgB9833GOz>xGTKa@ncDh!l zZ*vr>b0JVM_wrcdBi_AY`&h8>=YwR`=9vLx8%e-D1$aKCq{rcP62&yYZDuW;oO+6> z;rq+4h|*7@-MqhGx7!IW2x&5M2tSQ_xG2gplqIa0nysz6omKb59}VkP+ixz~BP(ru zjjS`*n!?mgzdo9_YBIj(C+ z_;LM#X$7UOp(Vwev3Sx)$-z9Y&{rO7hObheCD$=goVn9+x#NB;{gZqr;)jdHULVwM zbV=_?mhmA!yOEFkC#T_GC3w@}_3y*qiMM_oyqH~x;u1k|w{Mzep2mzmZ(1{j80w;ucRdJB zSJe1#PqZP(;Xxd(c?P?!I@FDdq&7R(OR0P-@gIh^z3d5aGIpxA4m%(7=~T3|hDKtt z0tX){7#Qnb`^7?|e6L~7Zsygb4p~9S$8lXXq#%$OouksJSct+RtD|SthhE@ULj*_^ zNJtUmf=^$i3!AZ52tF>SV2*dgMdas71anb zTGHh}pC}}O#YyF40zs>Z5-BX-d~u8tKT5U}_k}UB!R23rTYEQWC1AmC?_ z>s01JypjL|sV5k&g4!?b9~9W>7NkpiaW|J500M@=JhAE0wXZx8;^fxgu#3ajGhSRi zApzB*_bzk51DeVcqbsE)b>>eieGfLcj|7|?1L@YVuR^1_+=`&!u{?8L_o)0Ry|*_} zHoF9ukg}_+R%FJcjzD5ZPo+}RydU9>KgKq88pNknym7uL*+vFCk<%S(&BkUFaPmpJ zk@aaw-RO8$iQyer#P?B5u{FMs@3Ki<2xb|_UrPF+JU!vR4SXSHg2bE?|pkn=c?zNgkO006lA( zxbWVgKg4OS^womKCwAW=@NznFRrQYr$9HbCYubz4vH7Gw!;p9b^sg$NTunSQpq4wTXsFHR~vH~(!+NsH^+G(JRCxxR?lmugU*A>s&d_KB{=3B#k=1n-urZ5J5 zD<1p9ULb-;7RqOdJLjcgiNs>+!0w0JNpWBx!x$frCcSRg$JRpp32xw3G4Ct5779C&Ud~m;KFy^kW9l<3io2^RMO^jW#I`pK z_M{^?C4fDLdim?e-?WFrFNYd4+<243mKJjb%y!|oPa(!Y2r_x~JXhwI#~<6@#`@QT zb!hwrJNP$CWMG##A8M3yf)6`0?O(6uG_e_+d7}%(^?M&HUW=mr_ha-=_K*Fc{tx^U z_+4`^j{H$$ZK_T-T4{FVO?fMH$c!9-JzE2>TKKEO-?X2?Zyi~EkHVfW(qz=`({9U< zeALfTwD+&Y*gRX|zZ|ECwcj1;S9*_#j^iBHcP%Ts9ORZKHS+D|r9GF4<-5|ZCbD?s z%ufTABl0!Tns99j)SP+kFO`jO`1w<5C87JF91|2!UvK=yW1wd%ea)dCkF&$JF+ofi)Z;gTn;T# zp1NH==MFpB%BMUwWlNXZI3$DKs7R`KQaW>13EdkH;T2!^XqhKDtZ37+S2^QjJf_uR z#A7|GtEU8(!uwUp8A}`-k3(6~unb8#73orjrKGwPr7BsoxbekjJbx!AfOA)+W!Ojr zR&=lXoM#89&3aT}s97yavVhIix#$H_ei6pg#at{-6}smnih;-sLC0RT-x!IlE@$lp zK{*7~c~{He9y`^UkIj`M9<^1ZZMYyD^N!-XBCK=id$I-q4CH$8RGj|#m;-}W$;mhv z`qXZ&P#i8Ziq&iiU5ce$qc|BJw7{i$=XF^z^N{2b*icc}f(HC_#V~JD9{aMsn58?j zkTH*1cbA7j^6eeZZ>=v|neq9fi&`i=r3Q18 z-nF{0+hv3;xtsWU3{}Wx!=T7KR(K==FaRg9;--zWAPNT@=CjeGOQg~|2xL33cU9z+ z2}T<~O27_Te)9pJ#_Vux!C@;$3!-VCT9^PaRNz5=&Fj-Iup6ldh%1?$CpRcf!H;>%6R?c-3H3Tsvn zs&aWb=~STvM7<9<;;)P-@4Ge2&hBA7i;5gDX!3dJeJX#I&q9qM1G7Aix^r+cYi(njPrDhpkdr}Rgo58ed>!ld4+Mur)uep?sP_N63ENWNyr(;tygUC9Ak<_ zlM;_k^qasZb90^v{#DZ%S)DPSfKW1#>CHgMLh?E7Q>%^H8TY83Pce@neKT7obV6lj zk1jKT#YeXcaHN{D%3F{@BhsK?<&RJR=DRPP^brSk(&LA_)lr0d^7O2m*Isrw%hH)IXstffPWnS04n^*_%HpFAH}$D z^<7duI9iNG&e$0}Pvu^}!#G zQiI0c0+sv~dnh)~rCet2+n%f#;m5Ew`uFhH_Pza|zAJcU%Te&J#2q2$xC1sfzv$O7 zG5!`t@5ty#_pY^*<8Yr8T5rnh?^_w-Ybvca>+?=h!?sX1OK<$QT%Wp$&? z45+LmOl<&XjPsiO`PcPZT^r*RHZWX0wYI%~C11D_i65Mpq#I2ERSV<}t=qRFcs9MUwkW6Q?zHeU)e7eHY5K z)fVd9ys90WcUrxD;w=xu7h>VA?SzA=^8sD8@ZZDVi(2Q2FVBVGkc;3#;knLu$gga> z_!Huv6)&Hz>k`Lo>4@#)%H(IMaNf9MV=hJKJW|N`V@JJi&IFk_!Y0|+U35kHM@bRu_2n`edmBU$7=4uV(~O&rB=-5_O&mh zc0R1R@ehb~7M@S|_=U(ZVR9eaHJPkwJ~NX`Tdfk}OKB$BU0HLmcMI=T{1DzD(lnUh z*Fn0975&_dn9gb~TjPeArg+*71|2U@C?wnVpCp)x9Gsfzt15Vks-)eHoAXA`LslIk z_8a?obs5Utl>j#1n40uccNA98S~{5;MgWj8`PVV2YwNGvTC_It#z|LM6l1Sy>m$?W ziX^<1l2+OXUe%2ZOe0=i&1vR!#x2IhJ#WJLW~Hxbw=FZzd@R{5NT#TE}5) z;d?vnN!_H1<&*a+f4WEi09(C!+*+UdM%IgY$R&xwpI^qS+}(YtimUv=xa016{+O+* z&zhUG+Gdf8Ig1YuTI-$`wmv1$tOVBX7^R#7B|e~#K_;`cUjq0h%KjUO;=i@Fl24k> z-cmu&T<525mAR_l-C5g39jwKiw|@TsT2Xg2(7@BAZ!)RhxN*;=WkWEXDsBn3`;Efp z28-bB0zF~%Xx{SH;IaEG6UYdHKAVW{PCxqfuc;f+{QA;rf>?Ym%V`3fE>w@=_cgT~L$i~5vLhWfGp@8x59z)h z(yVkFace!3nZDM^x!uU>#~o@LKNDVGYc~;-fd8YQfk0f(B5TO@|XaZ3$WtxszYb!ce@>_D;G-03pfU2k@ga!JlO$EA7xv7tpD zi>+?-=o!`_w2+wV?s>0Y)NSChwh0$3*c-FWV=|St0gA)SeAHYd`B9t6$N$rkBH-% z{UU`4nDTyZMPqAP)R5W$E)iUhUUS~KmS=^8EV>xfpro(4%)#JK320s>ZDLVxCZg-Z z78`-}tDYh8bh1vCmJ8=3QH9=vIW^>(j)$!Ho5t~dg7#)r$v-(AdsfiU^?wdu+e@g= z<=QD5nT|;{;$pKoI7)C@9Q@82MkOy0c*DiYvFk9tbdi1Qa{KC~^C{I&{v#m|@ zCv(UD0BPTc3$3n~;u~3h&-PoNFzieg>TzB%H;H4h@GX)g>bEeD-UfW&{VVCO6>E2T zufyBxE4J9CBbJbEY>(w%nVuonZf$kVTEND_Lfm8cfG3*$Ca!S|&Vr?7c%P_vVV$># zl^UH-Xp`eD#*<|f)^jA22P8iHm2YoOmGalcuiA^^_3oxDw2u;9=@#r;akgwo{kd;` zIQFdAu5I-TX(M}s8wVj(eSK=4kMOq7#hxb2w+yhPqkA9muI!f&mSE~SxTq&?>gVdY z-5g#f9JqN|{l-6p{8y~q>C)=HDAg{nuVg!5#_GU)mol+_D(T9 zV9$pB9=+lCm!u0AWSZn$sR2fK&3>U2`lpBu0>_dAbhFdFHBVL zxQ1bXGwWH7A5rgAoC2htqoqpCmTtHeRz|@qf={)2l&qJT zVlxKMUHIhos^z%B0IoUu(lZUD1{<4?r9w*}+Qb9v*w;#ll;lF?c9lE=cmlKc66QuY zB=Rc6vTny1!91SzSLNJ;X6DD7f#9y%DdB{wkYLET3ZNEy3%)vjxNbS;@yef`4$4YK4!XC^<;j|EGGP_$O zNa|ZTe2g7eSPTx#_!^6boQq){n*0u>p|LCHudgl@37e{;mByzy? z9+goQRk+UFaaL5}$;lb-S(O==8zC?p={$HtxhIgqvdXuE=Npi zSss-N?^GH5>ilVjAm`Xs2y?WR;HmFgDo*USG6pO2nbud_<*Tc?GLf5^O%y^&Nw)&4CkiiiJK+263l9| zNJ8L!4r;ngHyb=6q1s7d)tbAZZP~5egb#(u7^W)%Gip*~h@f(NBSK{#SYGt<3jrESZU_8LJEjB-0>qAQo=0&&pQ zt-u0*hti`AOq{R^dsj>>!$cB+U9iq^n-A9%DMsHJ!|9rD9Hw?9E$_U=yQ#xz24Ve_=l}* zhd|JEJBS1VAT8}!j{NlZuc4=irAF?5iIbyJZqY~4n%C_)@jKympK3fE@ds4ikMi2j zF_thrFxAs|WBv+J@nR%4-Xn(I@mYhHwk9IYjAYl$5dO|z8hlM^HAy@>f8?>q^Opzm z#d7z*1H5ga-3Hb4+lysZ=Xw#)*URQBBF0IooUQpaf57%|R5LnulvB5+hv}DwKWc9j zd_nNLMKdHZI__e!e9M!_$rQoj*!8~?%^l3IB(cKWH_whZIqhE+cvjN$K+!R3eqoi! z2jn&B-Wc&rmaioDQWbr{WS4FO^Iw!>vWzVZM5Tvb>H4M%6H+*2>Z?Ad+1~>^GA+J8 zpAh+qAXu}O1TIfr)%pqIPZ}hi5@;+gQr2{g0frgK`d7hU4E$MXZQ*lq6sX=}V4*#I z#d|%!hR&wn+W!D-y;dMORFLfEzIPwQ6{^M3r=nUj`KyRCCtEY9(^@KR%@NRl|UQK%Tyi$n1 zP;z)apRIin;XP3_O>yD8Ee*oqSdrK1(zc_Htwr8%nH>+ z-}=>keMYRMPF*&>=b)9*>KeVZgv7}M?Ux{pkI46}O9pr>A`I^$vf;zFNj|mnJf0%I z(e>l@+2o!d?#OVU*H>rpF5d3yJ2)H%BLFGQdKoTl98GCP+^_Q-B0H<10)Aq(TSHSlfR*2PZcpV+x)G(p0Tt7!8S7tVJS9jg$cWdABf64V18&2} z7YWBCQ($>m#ICL8W17djx{$=UV;0lUQ?2hr$@0mzLDYlRxz(cXOs35luW;o_F<|n? z)6%x!onKB?E~Ptr`_}8nHLS8mG}2=@U^0Dc=bwolGhGHbC33|<{o@1BXa4}NOC5u# z=t^OP z^U3Slx>?)%H$+I+F~^KC139lfNTs{g?qxT!vu7ZM>F6uPuR+E!Te16Sq;E8~UK%NO zHx77jTHw4(<3{l%!q{74CS!ov$*P*=hPQPKE8R&Vp~|4-fnHXg9oMXUX)W}6gvEy; zOnC}D{{UL@vAan!7wA49Pp3iSn=El}zgO>rReR4Z^4AO8Sdb@OTxT6km0 zj%JXmfsnmVdgb)3Z^U}eqZX13mg+%QnK;1z0PEMN-8YA{O&SR`R*4)gBT2X{KpC$~ z0SLyNr5LF9IQddu>pUk`)b3@{Z_*_RAC^WMJ= zDJQjly=wP*b=)r6d{A3Ozjk9IamcU7FWP%dpFsG^b;VN5(zfQuxySRbxZtNkwl~=+ zd`ipI^!Q&E@OhjnT(UGzH(1Or$rJJqW9eNEpJjEYU+uS&Mcu|kmal=fm<#9CAh%%vRx;WLMH=Qk^-vRXS+T>O2lMjYuiSslVXyu3F5E73Ivz zJx?d-Yv{Xsj}X3#_LsW6LL(cqJ_!0(hv<{frAHc-StN_@XMowR^2=J)wRe`%8DjEc z11uDrAIm?bd|i0S&FHLqj#S+w-sbFD-mey|BTaJ0cpEv(ZqHJ9*k?+#HM_0NxTJ`LPMsQ^~Cc0(MD&F@);5f$+r9u!-sf{7z?L23# zQIU@%oG7a@Gh{EzwDiSLmPPrO49pHTiuLg6pPnUlSCpQhoMW2Gm5Fc$0QD7iSIZn0 z!0HWBm4}vlSG7UvjS^cG9KP(YPv=zJxdh~7aB6pH4nQCbXEjbja0t#j*QZJ-FVKXM zfsQhHCaTH1%?px1Jm##i80Vlls*;k;h2Rs`x>CC^sbra6Mjn48VD!&QiGc+i72EDI zYD0l=6m2ADB=oB6cSp$|g==Tj#U|M7m4qI^^#Y-JLlV75UTIkTssjPXdWpGB+i}Ng zYAW{?njmJ&sRw{)5+5`5uo-#QGhS}wS2Y$6}YE9Z>_a21vOO3W^)i)J8=GkLsB2NC-sq7REJx#3K-{=0#Ag7Ch+qymByozJ z3Bg~OW08+qhoGZ1eMQ@r2tmeqsdgv5H5q#R#F3LpSV~IzntMcgWHN0oFizpYHEYeu z;DPLGDI`DM;0}kaPLAK*I6UURER)vdNv_6{$jW)?PxDkEBRMshxq$hYpL&rd+r~Eo z+|(FK*RwPOjE|eQH6Gwt{op-no4SQA4^Gt^%y)Hc`gX0UN%Ir-ORV`EZ(r+6y+Ftq zIO|jdgpZYu@Aj#_VG4JV*R^_7)9Pm!z02i?Ibu)K6yGqcWRObdsH$c{TZ6z9#hJf| zlC`#vV2p0{9_^EmbDE8qqU7fXziJvqAfDdURLI2OAD2B1Yfcwtiph*-V&|OXaaEnm zHo$r>Uez&^FN|PSbCBF|&o$jj9nIpcxZmRB1|HpM!AlRjflpJlNmb9iI4LYn>fZyuXT3w>Hm9w4d&2rMyG+cHM2gY3umh)VwQESe@SlPt7CKjhpoFkt zm5c<>xyKdb+82myJUI-c`Osg?+t@0x4i7`<4D#q@ z&OaHBu9BSFUab0D4pW6vxi61?DQi|yi(My6(``~!K4M@JgVw%B@$ZU1wURjRqamGk z0?(7zKi0ipT4?6eucd*bd8H#8`DGs2uQt5XEvC_T-`VfGVTES{C^Op?&w`}sNi=;E zrAjopQalS*xwef_G~LQs2xc5)r|8btL})^{ez8wx73gg4X+=F`MF5DiW7uedX|YL$3TCw6$eT z>_^N79A^WH`Vv0@_|HMmQtM6E?xeACgpO>GJ+od3@CFr=;N^wHFvzz{hK5e6#A7R8 zX;}E~8_x<|X$0HcU8H#XG|Cricfqg9F?Hz25n44mwvXl-(2v$=# zAtNAkHRAeDjBf9&A_XONW6!m9(O*Rk()qDVyVUY4s-`ZLN=i^?p+=&Txz*m^P5r3P z8g5Jv#+?qfjT@!Hd3YRgRc&oqR&TuP&@g2c}8Awz9@2xoJ z)m1NjZh5t+xckWYk4W(J{vG&)k7aWzS~S^MyK-yoFAhkTT6|3_{GmBLtLJG}JFBR! zWeXEV-ymM*y(dlAW3tg>hD9ov>z-@L%yYUGAp7m7$bxsZqbx~cj!w$$vFT)UXUmJzYWs9iVTN+ii#S>(f z+9XJ*?&zm{q?5STMYWqvYbm&o%SKXuQIg)(-CMe|%^k=FATXecf<;!EHAtJw4f33I z_OGbR;Yy^MsAW=<<2{jbAb!iUbnCQRcS0CaVi;o-Yaze2gL_qR*RreL| z+WovUSvL3#Y^j789FId@bg=2#J<}QO-V)2WDzDzpy?OY|BaEG%hb*Zyt#g^uyfY<^ zg7J%VxRKXrc{(mDI7%|U$Kj8FuCM$9@g20SMmHA5OeyCW z&3(_|d6Q9&DTz@T*1n00Ma+ z@!r2-#pc*-+Jtd5z9y{C*7$QjaEgQ2_6xlRHMx#MkcxA(_svbFPj{qio2`&-KQ7?C z2l&*nT}h~Eh!b(oCC_u{D&3)$YtsawV?BvD$gcz0t6ECu-Bis~z7};+{fYFcCAgYr zxO11?mNNeUhtjj|?H1bBE2tTwjhiAi{vT?;ZzAb=Wd`7~@_^)hD`HDFyU~*7>e^_d z`^vb;Ks{)LVGA4;G18uw)bssv{%t$Mw-+wr8Eyep!(cZR;*u}}?-QO$CpoUy#+u4% z9v~LbIBQ#T@|7L?ir}O_Il`zO^=e8|y^qf`Y-6ooM|6lKkQ@SVGmQJy8L&uT2qUTW zt1}&-9CSS@gpNo!$OPw_^(ZEJ*6LN2v64ms@7kzH%1H#(nV;v~k_Z)^?Uv5b^{-xv zu~G6OkOm(iBOPjlnA*d04@$8km2SXdsLLi>kb3ZI)upProVt-n+d_<6gt~&t0qf~VPFUa&J7$>NKyXIx z_0W~fqjc;!wwTKkf;beUD~yqq9XaNigXM)F9D3A*je`RRz9{9p&>VHS5l|N;Mmtg{ zR%|dJV~UXc$BsGUH8QRv%K%TcXyQwqkq8T(OMZ8$BCJ5z}1k%D<5kt<=C zQrYf(dQyOXUs#(Ot4ty;(^B=biY5J%%dd<>IWMV!)QhmbQUL^)Bh-WA1S|n0#dIAoA z+0As)k5ZzSQO>6zV=L`U2LR`>#SBkI6PO_1bPpxW|+k$dFwI0$K@sN3~Q%MueeNDdw zIgiFr!U8{f+xMRyN#l^U*AOU&TuQo#?wxG$opO&%)fT&UsPMOh+NsV&FcxK4~W2Qwg+!Y z)Y9OBJ6V$AH#4vzGF$HRo<(w6DobNDX5rdPc07`BLHdf&@fV5TNwHBBCT5kerBj?5 z@-Y}!DRQo-++i~)!6`E7H3YCTtF$g=y*b>lTjs zh2G;Vpb)Mzfl)&uy0c4Y#vo46RQ?9Bj8qpdW7Msf$t$I}2^|qFrEMWMeh9L%+z;&wkCG)Ff#CjC=by9JfZAUX zTX=@{7nua1nVECHoSwg0`)s!n48H+a8&^b@o~P$rLz%k1>|Tib&)`;%sp#JgtZbUX zLkWywazG^a_OE)=JT#Gb)9sg*MHsK#a7Y;>a%-XR{=4D3PX=sAA#0Un^3#CGxEaW* zn)i-lTWKENDWeYIaIxeX{0?%XUCOJ~$+!3Fennb;yltM9d!p$E-5jN&#k65@lbXYi z!w@d2Zfwz-SQs1-03iBRZ6^J-KO)w0sM|vTMh$iPx=C;0bdek&b{qM@IP^8|`zTeQ zowY^NioZ3qG4-3JvtO~v0ELimUYRXe)}ATbV-npnfC&sMqO;SjwTWV$;~`FWJcsV_ zTz<2rh!$11o+%*`VM*^?IBXiJH6-;msW~lH#&)Nvt-b3=qy%BOF*VPB!fXK3KrFwg zS}`+AFGKg_yIEf=gQa1(z=FMmMjcCZo z^6p*$&Q2@b!l_}QcJ6RaT+-C{?H+rnh)E=kO0ORE(A?-Y`i742O%Z0t$aW0Zjp=&C z$rMwhtYlmgroAf1#uKzeN~)zsL9W~$CKYDxj`~$2$!2sqABQ5age<{8Cj&jJzLv(% z?CQ}(vW|>TYVrZ%Yle`?GvNu!=DK|^#HMN1CoC5k$75elft5IE%VT8W%B;@n);MC2 z75ND1&0C)KWwv1x9yuYYEMbcHtecfn9<|U#rdzy3V>mrYuco6$DjEt-??cURCLlDY zt91ggA!~oPt1${m=DUqwN{NKK1|weMt$Ee^$88Is061)JKA5kQ%&kU#_fgu)=V^C; z1*L>#cDil*#Mh4Nw@<0wTt^Wq0pkXrCEWUf@)lW2FF-rhe<;Ev!jMAp$E|o6{934& zF2@|)r59s{nJz8wV+=;nbI*E$_f(OhkOD)f<29kFv(Ie85M-541XeOyTsFp<1BUy? zys0H9StHMJ*5;pvW?=G9bt;x83!3)`b-OgShBC<$6aeQH;-6whw2kfa*Z?@@mMa}W zby;M%xRfX(3yjx35}fERSiM>3I<`sJ_K&tj_M-4zvy;IX;Sh+<5t|vF_oyU^d;4FMs{hWl3W6Zu+4U*H7hOH)+w%t{N?ka;jIvybTjV74_WDv;cq>y|nI^iQc~A*Mld$)$ zfxJQehb%DO!WA=($AGm%TJh1hwm)H2JILg6PrY)>1%+w*TQ>R$N*8C0{9X8NHU9t& zP9V1pcq4D#1Q{o>ugnc{>s0VRjHR;GE#!q#Oe1aEy9C$lqv|hxX)M!ugMdy)t$fAt zgW(RB@d0NR@kS?A%9R)(^Uv3s=*hFJCR<%ntE46P9heMrr7eCF=AR4vQh?|XqKHJD zpMFU8=DpX$+UA9-=@Q)CUU@eQ9#n!kHSouaJ`DK(0Kl5dww@)swL|g-^sEo~O}u5M z*_%tf4&@&hGDHsp@UPN8v+($+sbQ-rC+3qr=K;hq`%dTSHjSw1v)aux*Y;smutc(e z-rQF~KZ>mN0S=3zUBjr|O&b|}xdsr9IrJ6zhoyMG#2SLVtTtNA@;(B9r}eM7J`4DA zT`R#R;_A_@?`}t#aO7psW8WNbGArgdvYNnQB_}n_(OnB0p1D$+j`p$VdW2@*Ueq9L zmr2g@PI)ztB!J|eP#k1>*U{e_JS}B&q}%xK!?yOz4W*n=c$uJ68u_jMu4Igika7V& z!oF;F!|Wg*n3fp8t+J>&VX4i#-7mcP+$Dc&3;pDBl2rF1v)#YF#afi?PzG{+YJ{!0 zeBhjVSJ2Rnj`b}{a*V!mHjcHOD{y)FbJSJIhFduyanh*D2F<)+^~HL$t#O%?Om}U_ z!Q&>f=9!b^Ot2mOD*eeQHiO9Nf!eZVELd_#J$SETlvT7cl!zSeVUf7~YC*J&sN{77 z@k+6d#FOh&c_b272R%Tpm8Qlwvm?VX10x5ysP+~ZADQV>6NM}OMKF*UAm}+2acz>{ zVLoCGNXVqY2RR&yM#kgUBy&g@38}4n699r9cFZdBsB-hHfxO zg(`8oKKZ7cgOb~+$_r8)rJ&p} z$T-JZ5aMOv5y@a`Qm1KLj=gF;4TF*fJ9VsDDN4ce;{>x0LO9Jh1Z6)jPUO=_1%7Xo zcBv6T1RgWep~W;D!;muWP%=B5)W{DfKQ1~_DEXO&2s{e;MOvxO_J8)AyDCz zVB?`YRgAIcaQx~q9_AtNx#?4gn;(5EK0+@OS1a;>!zZz+3C38Hz{Ur9stvnvZm23^EDpQ8`_#bCc8STy6<%xe|`7 zon%eDap{@^tB^x-2P3s-yn#_ZQ@_yEO){%+M)ER6dK9426cSdsqGtf)GURbpvVv*wo$J3fku7KTt0DBtbL`10=J3;IIewDMNXtz3~8l~J}qqEa3)?2B7I8EmY zIPP$9pF><3wADN;wQ6X;5p)|HtN#E8`1bW|oX4FvP>^Igoji(}9+d9R&h6jWGaaA?Fb4~E(k3H_AG&c5; zL%Gb750G}va-J#pBvS-$Y^p zK#WHJ0I#p(U0H5PQxQ{|qUDcP&fIow7X+fMV=u&4m!A}VKhJS)B%e-6@dkQr&szN> z_)p-ew10;2m9}?JEGSUCufNv38{m(^h~Ux%{n~j00KASk&lm!}+VBU9G`%BHT`yLQ zL28ZjPo6M3SBb}*LxinGU@56w8mXQt2(3tKeg~X~kOcRdBHR{%} zcy`9kp8cdr2>{764VlkjT;Gg5MWLpRyGWV~sX!;ojAgw+W8Dc2%8!3)`PBS4@dcizWS?%j5xm=3Kqnw~Ij>q>A5-w=gqJZ|OC{1UQ0!06 zr>%SI1Bq1C?SCdNXU(q0H;T3GZ$W6<+G109N5*y#eJei8P}MctM=cxv?D2#5kNGv& zYFbV1yWx=^lwAV(k|19Fa6d}G@ZGJ|jmO!hw`(+3{x9P9tZ=k_ja2rz6OqJgSDK}b z>#VCHMC5JVyA`v%t%0>rgrgMc+4bS zXE+z^<)b-`J|L0EE+F$b0SW1WS0&R7mxbYjY;1!V=DJH;F%)7upjo|0;<}3+HWvQ? zTNyCptz@}nZhc6U9Ggh;>rEC|ulKoaoeg>xmEogtWL`o}dSKIT?d@%^$Vmp!$19$- z*=Rdw($yW*9AprGN_ZDf+wvn?bYE6wTX=F9HAscd(iL%>=Z~dn$7gA8s!Bj0AG?v- zwDl+mjU76khd<7_!+SWm*(Lxd12y_xS`?lZ>1t}UN1$nXyjGAEWJbpyF{^U;l`v2O zgCD|c&ti}fg2)DYHfs5JBr2c`;|JQjsN^QAh-*h`_;6H)@!)QMI3kQUUoj0wpyD-xoC1)J%Yj$eYqI#iqO@q zZH=pWaPq?rK(43AK`FrbLw*%XXqBWO$A#-&SJdMgEd--yW_f+Lg@w)GY?zmKZsM)q z_-w@%BYb?Md)J}I6hCNK(Cs8=ifpJQyG6$E1`Tsby51;1G9`(fQ9}aXI+mrj7 zHQd-@Q{kYz{GsV%Og(t$EI;nZ{1zD~Vr*gQuy3f8cq zot2iSFQa@q&@^3KGR1DguHu;@yCWnPviT5*l}W*HIyDq-0BN0$%fMM7?3p1z_9b2dh{Ok`iBN_ zDy;b{Nm=Nf^-XlQnWhT6r(M%)S7YX>8zoK;Op2^qC`yro)Ec*WZ+B&?+*;njJ+0gh zW4MZB+VQa9s}E3ktmcsyQ89&5=)7%P{At%^_UAdB>$lhvoo-fzq~!`MVRug?I#KHE(Deix5wI zR0)$OLJw>XYT!WJ@r-lpT@;_06SG?gpoCuJ(@xUEC-A2Z21b5fPJ7gUF?C?QM|y25 zHc#1F4agA?PFQ+VPTl7Y0UeDMF=lwMN2!8X{0~Jt}lf<#yzA(y!Sf zhO9vJA22w;sdjtR@uA<)gX>m&zxEI1S;~v(N?I98><`@ef0bAg5*1UuW{u>Zn3Ik` zsbh1w2K*dzUztiVVtVdqtFerh3+zoo(wu-omKmlr!u2SfL`s?R%aBsS(g)k;ZsDc;=IMJzRnNOY4GIgFN3 z?^NF4D)S%?TY=uFO({tV?;%e)6_)ejP2YI-CcSDnTdO2&mqT=2A2q#4dYvZ(l6fpS z!LD^CEac}LbDFsnzq=fq*L*OtwxHszsn9IPVA;ZtQ&!gC>{2j!=CBe#$Oc#p)ueI= zApE1St8^ME?PGZ+EjBVg3bd1{Vh%<TEmU@GL>xcjEc1!g`0Nol=bzjq=>uhZ$`k5r-N4`kZ!;kHHRFfh*6P> zwz8BXuIig3OE!_Zl4qPQ?!v9dHaBnwpcRO+0KtJfu~t@Lo}@K2owO5=Ls?|&o^#U` zID9F{2aMKiQUWo~bDFY^yLUJ}Ijv(Blhl-pd-nms9R3wLaybVi)f6PIGC&@cWnAx7 z+&c9&5}HgLQ!az$p*d0)3`TqQAJ5vpm$2}hqxLY;^sNro_Y&PUzv8RQn`}h#L@^8~ zLda1=1|(1O_?Tz*ydW}Sbo-F#J>MAkLc@TQGC z3k|`!aN}fwh{R)n2*K@)*XNvbo=*=-G$8ez?(|km{tw`B;+$2ykBvSkcqdNr7sIVC z=tmj5CoxEior4(}Bl%ax+TX+NU2Z&+V?2qwtZaO?_Z9c+>usTUlUVTd>jm6)^SVPO z(8%eY2+liIXkSdYX^fVz1svg23h=mpj4^pN7fnZ*Zne79%7!V?jh?5%+DF0v01@jN zjl6N$NT}Ryal(Fe^#1^Yz5v^362o<_OBAkf-d-|2$LU_*ZK>K>`AcscF-9?xsxwrz ztzPHt@Laifjm{8(-1||B@eee|%~F2kSv4`$>N_W7c4?*ACx_Av6hmzsWkRSp$Q^5E zR`_9asrU^w4L;^b?>3g*XKf<4d`n|5372dxRE!?@z?m=Jw09AY5k!_@D zH@;oDirG>2jQ91c`Y(uVE_5`2MH0x%@|@tUTmJxrV@|uBUSiUgJJc!Z?rZIEzgKi2 z?3caz9Z`+_NbYq_HeFbdVBV}2JdO|f&2HaX#j4mU97`N)yJk2i>scqk%ND4zgB<*P zxo#K#0IyYF#P<45u-Y!=Nj~Z^?_F}n%MRZ@w<%LryEUy=-pbi+Jf)9u#z-AIipJJ_ zFBQ$2%LtL@-MDRDF<2VjqkDCE6TptHjt>5S4|?qFHR+Q}-!maNz&@N;E(yBQm$X_H z2trKr%YU@Tts7MXBd@hxI&z-bCuV0(w8Px`9?Y#hr{>pZ*$~aKHPN2dhB)S;h#?V zl|zBlSCmU~Bh^C#$4-4K)SWm{sH!J%&J8UOa5t8+=%;k4=7Eu#^KE-lf;1&$P)9sg z47&dSl8nMZfyXAi`&!mb&UUyR`qy;0f-$FQGbz+<9Wn7sB!v0cQSVmb@v_Epl7=8; z6W`d^i^(+3vi!g)=}<=VM(m2@amhXF;c=PeSkK(s)Xp^Ik@QWki>@xB5-f_XoO$ZGJJ*P5ek&2r7-v);#4FJ4d_`p}e9F1%p!(Nk9BOjqlhEjMzUItc zV@n_;<$1`bO>`}#-_Cjp&KljaGZ7;0a0ec=f_rHkGVjOU2dS<@R?-7P@)}p#`}xfa_)~(j`|yYDj6j!yQuf8_L{wg+yt_t2N*mKD;3h%=q2)T z<=`m-xm#;TODEYl$pyGQE6c-R(yF%N*yD zc%+`r%4>C($caXRB90{fCk4Pcd7uJs9Fu>7>s0euK{q{s=220G4_^LNQL}6 zX)#$MP}{p2=k-4fygHOu7O(^;dV$`$JvlDzBy@Qh)mwsVX6EWiEH)#2-E)fkw?512 z<&~3+uNU)2rH8dh>!Hi(-W@u@xU-$$-y)Ez?SOOCbgn9CF8mkbORWw)NZKypb!h1T zDjp&jr_|tmE7hP$6k1%v5}9}7aU3tbT=7?fP5%If;C}44})F`@z00+L8JJeOtIE3Y~)nmG&p}H*Ki6+;DS#-;a?Db(jT+E z=fW==Pj{ikcYWbGn}${M8rPHZu^+?JpL+hk;Vju>uoUV&_I|5F)8w0qlj?k=_+}${ z$vjml*DH+VgWj#kq@Zk<>UU=&=~?p=&N2>r*WOT9j-sN|x*f~C?kVY~{=LdmSr1~P9lPK(EPJba!3x~lYrhb)W zk(-b{Z_<~`+6F+~*Z%;mTJsaC*$ApijC0RXR?{Pb4@!h9agG7(J5{*OTWJT5^>C}o zOMS*N<^~wR-PF?zO_g9kIOuv+;~8lBuU-ae#vhax{4rfrZfl#J5;-Je(xmHj3gXnf;$?h zQ`Y8jx*n^_V;T0X2;qKs zltwYWrm~M^kr*sV|NBKu2deu2* z!xMp@dX7*7gSR6*;MECa0hlSpdK9UrC81G@Y>MVW+1>h9a~0$()=MS*okfH(+;al{WwnZne>ClHJYGBJNNR z1mdkD?TnS=A6mtY&zKmKin$boL>JKWS-NS7zNX4a&+!cNnzI~(zB<-8nYwUSwmQ{_ z7tdQg|=XW)2WF@!&5;y|6-6V-i-q&Mk zB~pvknDsq{UxmRe2LuYkg|QzdwBSE*fKNX)b51s4%+u7>jhMbLOJ=VEK>51*)d-2) zGC=%!tsp~Vk@!&y8a33j4&j^}pHo&5hT`1y=BqEtaG>MV)T4upaC+3#X&Bp?+_xK? z_0K)3$~oFj(!;1DwNOx1!=O8R=B+N%v@YWzJb~$4?cY$kI=uq_09J;}#P+sH40f~W z!D5>jmPvv6Rwnhy2OfaexZQYK{{U3*AA~$dWvgmeT7;T>f7{Z?Px{>Kz$cP0qw}vW z@D!Gf;%zZ5qWe=Rnska)0WAtH1mm7ZP)0ir4SRl{sq1j~F2*fdJEXL@yB}hKlWtTK zwXxR+uj5~c@#b|Wig1K}9X)s3?$q)zF_fy=9#P^S3twuUC}p)t7G7~9{pMBm_o~`g zhp$rPK_n7L<2#!Mz3=-j=3QZ>jeMy{EayD@-^#j;3qrRNypytq#uyP_p3~wQvVx@> zJv1wkZhY#V71ch`8F*a=auoVzy(+`O(%)&3{i+fYK7=lL{{R~G>y08ikDdfl-|pm6 zLeHnNiGc_|hi(OPEY7uB@Qp=f-3PHrUgd8G&3y&g(oARU$Up=P5`F8p)NO6wR`TU! zQ;neK73T}$AF^ugDiIhBmN?^|O7o8rd{Bzt#5T(v#`!m$#P!dmeXd(pF~YiZ;@fP} z6lW=U9_w+Z$!BqHZ6^%~1V~r0^dF^5VXf-6f#SBFM({Hu}vn)geA?& zeK$Xdw3V@vHucdh}^lttH80pApZ`pv!yMjm*)^K4cuR?_C9_h$FCshT6za4e3}~y4s7!XrtN) z?OZ+8*6q;m7#te;Y~FLid$DEGi|BiU_`xo%6h|m*9y(VyKZvGF?=fV-&m-6AUQ=&& z@G&Usfzz6|E~gyO0%TC@=zI6CD+i8sY~GC8Nwss*rPm~oGfL-U9u8}m)GyLF%Web~ zEf33+mC0y+64SIF+H(-QQ*&QCMuSFbX6oPt;*B36fvq*O^ zTy^v{g>y5>xrr=u-nm=(*$WVMmG!SW5S}7hvwS`UPIhObe`=)I{owg{Dmv5Q)jx&y zvCmra1=lu{^QwW>vsP1EErK8Qt!I=@?WA_kEwkA6WV#zSp~pGmwASl-qX`IbG6rkN zto5n9%x~NX=xeR9zuds&vG46(T}(A>Kf=yegtWCsQT?xT9nm|=^VYf>UlPydfLOB* zhPWASk=taXDbEB^4fHTMUE9uhBEFLijfd5_ukQ}F8=5I3dabXBt_|iSknQw6Yp9RJ z-b`S{FYhtVO?YGLCNbuGoiHk={3Na=0x&Xrn&!jf{np;6G%&GiQ{9J&#J3=MyBMB9 z@9$oPpzAS~jpUI}v9FgcHAg3V5xks^E4S0N`6C6LvRi@lt}0p7pn&b@3Fuf6VkY7^($K|#=4B|+{FDotIg-u?`Mf%Kumpjr$P3O%4K1+oPm>HNgVxG zlzCBugkt%b+G<`lbuve=;l~B4#g3$IEn#wYoMew*dgO+i9mU$qCLMFg&2=!FTWfKE zJpuHsYhvYAJkC~V%}Nqwo15E#2!u%ZKb11aRxn#JW-K#?&!s}@WP!^4n>~15SMKgHPk0z&8V(aEHpAD11#cskZT6n=!Doze7fSX!{3j~o%ZQz<)U48)| z20&XKduF`seQI;V$`V&J!&Kyzk9N~+blEhgvVE%=?f|WC4<)QVE56g@M*AaLG$D+b z7(f2H@oO&;7G_nH@z_<1?-AS*(pyja)QdrvWS5dmm-OY+R9dUWR%>kw#~55yl1i>*q|E312iD$z=SgV!LA_48+id}kH6 zgKi#q1X_ZlBxXn8mIpjzrvkdK3V6o<0K!)~YZs3H07=yCh04bt0dvD+J;ph&-m*;J z4T7gmR%$YB$#vE4T|u!WmHerqBC(TJY%JYIUIL&lGo>998 z7&~`$%|WpFgkkyiGAm~7{-6%Ig?9W&h4j%vYVD2Z7>83Y{U()oY9B(W#2HDWeg z;PdV(O{!maYUrZ$)XJh(5;b1qKJ|ViUOJKQ)}U1xQoS-WS7RSH$_VrZwrI*O`xX&$ zgLhh+V4^TtNp7N_f&JF}sieBIDY;zpX)t0q$6obW*oF&@ymb|#V_*nS8mcrna#ZI% zLs#W=tk$Ptmmp?5gY123yNoUf&1*DeQ0^uTFwo!$}yfjn7V*$?s9@WAi8+ezmV6kOtLK zRQIZmoPoPw&lT!IS{1PY$RjFAJ*nGBCnGuOPTG9LEx1#h5t2HSftu1UP`g3@04#@G zRY9AuC?4z+p=hZxHms~QrRIOen>Mhk*R9Wh+>9)W!>T#p?49&1_w_eebY zR%{42u6Ql?t5Osj$OM2J0N0;VO4buscQoKl&)lA;HKh_RGlNv%Bm>7d?N^kXFGJj8 z*0EP?tK70PzzW}$NrEs~6HG!(dE7ekDrGnWCq9)Dowo~XVdxI+*>0bAwN9HzJF|oO zaw;v%amIe0l`6`SMdnCKs3f0pj+poDQOvdpE9j3#@a~syt9WKhdn=2-_(<i=NU+I(O5gR15Y(7!X&WNi^Nu~ue>?GB7FF?_+s5*L z*U23J08^Bz^Gihk03xQnYX*z)YHcFT*5Is2tXGoEM?aNiU5mR-LP+IP2yTb5u8!+R zd38B8$B~-sHxf5fl5;Bz47pONyz>S*Ry_n@3u#6`e*U==72OTV#$!fQE zdX)0p>8Q;v+zfQDBOeX5**+k{sa{Dus2pWC9iZpwUqe~i#{|39H4EqtD{JkxY5Xc1 zw>=GhiH6TjJovx9AobU~0-a_Uzi+h(H>!*g|Ip8c= zGDkS7w@n0P325`Tt$5W{7NVZ_yEx%F-N~4?+GX64vhQ^m>HTQ4@MM454|OgicJ6y0 zQCde-jwqL7k?Yf?T!&NzdWK%dIIm|1n)?;Vv`pPOMe`c6TZr_fffRte1|3hhOG0bg;*%YcZ3J}p ztf;jo5Pw z<}xTb`?;(Zy^rp({Bw$mTlf?x0AzHBcukoGg4}NRH#bwnesfAn&H$58fR0{&b6BjY!aAeRtA%zu*1uA`66B7R63f1Sl;EFQ<|4aQla}pP{@jRi9AdfN z4aY=}Hl`L`k3z7z3O;^LIIgDB{vD~mJB4`UdelmX_t;^`6=pvXENraP4u4AWu^Bw- zbUCGiZ&T>I8@P)p3=0u}0j=oo;f@{0YmxjX99PV#<0XzZ*(#Dd=A9>xQ_IMea(iZ{ z2bW_gG?Z?RO1XVWY>%QP@g#QAHVECNSP8f-o@ zD*Tef@-bag%ki?8HNHZQQBo@B*s0=pA&Y2bCvO?WQn>LvK3E%-N$xS4`B(lEE1il} zWXV4$0GcG%^~=O>Cfa!)pu+K5Qo!P#oTiH_Z{n4Yqb_yWzp(ea#Oy`zA;an2R zaFspz)+)VBExseTxcG-^tl#M%C>)&CA@M&;f-{?d+~hER59Lr>{2PQ^Zo0ggm$nZF z*w;yA@UOyFEWTx+xMFw*IH;ZjD1!H!XO}Eq9yaB>Gps%|X)wstxOUYYS{ zPP+{2I%63Gp5I!^xbSy|_bD1hp1^VUY4*Pld>t*<+9uJWau3K1tQYbIyxGGggSt|S z`_9FWgw@h&$Du>t8wP9s~G)qgge?eiYK@zLN}IU|*0=K+S>Fb~V_4XkU1W6w_icwwNRhU{szDJb#j&$WiF8p`#DC}jQWmw73Gt`BziP)NWoQ?8%ZOaSCjaIz_IEO z%RRXXGa+5T;~?iX_8cF^HS+qZ6<+BkEW0p`7S#2NK4$p0J->=RB+IGk$gc7d4#9%n zhP;jKq=IuCu{3i5jig}L)3!ej?(H>~YnC?%Iu+!vJYur^bKz*E@YtD=McgOkbzC!h z8vVmA;;b$rN-IOAt|p7CWY3*&+Xh!Waf-B&Gh62Yc*&`Jk1k&>LQtW@1I0}nMds}; zr3vE)C-kqaa!Fkd?!{4T#B-jR4tdRVQ=7e!m6KO3MwomI@I`1sj$9H{3ab$wXCK|IIB-w`JJ)KGdz{jO z?oN^O{?V%*Q~Fe~rU3*FM+T?z+aG?dE11agk|b9k50;^5$@z-~K8CfLEb`nQ)e(#y zJCoGc<*6-?Pm<F`s{W>1K~Ary0q}#bi$wW^9aOk}I~9-#}@$V7zVS5ymrB<%nkt0czQF z>++H4NT?-F0o%}XU68Eqt|fcwWwcw15?BmotL-ItIpeKp%e3Pez~OuP)JUNKE0gJ3D4t?QN$0q( zO0^rh9_X_Y<+3)PL0S=~O~4HE#Z`*S%gq0`Z?+Ja?mbR;temwIiYMs%a53#q0P;6`^HCG~!U#U!N_iXsoO;$=`&?-&78mA1 zdE?MmwEoW?5r@W~wztFW8uHZL>2}x6scI_Ax;26XXWad^?+Mqfc)U0&KyWa65^!tp zAK6-c2f-f$d~xG_Qg~MLS&~gAB}5)*NRxXePu*58*yMmXuP-&ssbJ_i&#uPwX{RKQ zxHX&Y55oQq`vt727_+vXTO!fqktX8X7qH7W1A*&bJKO4dMxWsOYghy;n2QzzX=2>+ zJ#$`HtNc-u#6Bxawz`nR91Ud&jEsdjKi0S_?-CfaNg7$@42`v3Q-X2zufg*?>b@eU zv!PGR^f$#ry^vVth`OBhuL>S0jjl}p0BJ{! z(<}4TL&cWfT%K**M2-O6`d5*H$nh9@t~C;UPdcP!Jz8hD%dXqCkasFvj&X|T=fAW+ zKg-Wdit$N&ZERy?7g4U?Q&@BO)*mI6u2(%rHMTD+#p2~=te4^?fs(b4aMU%3Vz6dc z0f6Hb#5ahZYl5ss2ls2sZhUHnGaF1Ax#_%L6i&>t43XNs8aWktZxg1DT_y1&=&N58 zExariU`{)l$G`DZ?e`=Md*IiAH;s{_+N5W`Dyi|11e~6@;=5^Z<{?j>+LH3Q#h*hb zh~1(L?gj@nZVwkEaP4V^3FDgiq5Nx=DH{`$^HzKKrgwZPC3D6rx;Y*t@1fI&%V+Sl zx%E80EfNw$iZQ?>)+N`8$e79JE;GgreDFL$e#}a%mGr8!c#8C{(yR`BDE|Og>dpJo zI%ShV?t8t@ivu%mm+4%_rQ#^0V~GY2HRF=%dZdJr6EdEJX0k4?^9@GB*H`j=43}3@#En-0D@S zL2gHJ;t9(gjCT7}Fza%Oer97=8$l?3a1Yj{k3)@{hrtJ@t#xx@RCGnG+JrX|wYMlR z?StvmRIzIk6M$S~W16!EhfvDIv0zUJ917801`yqw+*d5?VHSo}GfFag7{^tR6&Y?j zirIr*lm$|)kM9bVG$>kLRE~MBg408^Kp3cH930mbd`=eI9F=n@G-WQgbRUIsdlD+b zU+Oc00=;(Dx&#vA@md7B9>NMX1y#7;8ug@P(tysMARk}%m6mgJxsphLg<91mYRDk*5gIFw0 zPFtw97>bqTz1O*67T|q3uPYT>8&!Ld)bnLe7caDXj+fvqCJT@zc;j^JP!U~}ei_g$t=ued zWc6TpHS-hvSd(BX`6u6>=S8o@iDZv5+-Loj#($kG9wRY@IVsaQYvuTwo66_XvkfZB z4bj5@MB^ZGYo5RHExbUWD-wgi80Ned@8W{WO8KC1_c;Fm8sPPB8C+f*#UWSd2|QOM za5&2CryC|rGU+dj`dPeFYSRPfD>?0+g0&*?4UgH@StU?0z|DM(ZK!Gl2R9gzx`0k9 zEAJBCLXMAc+i`{Fxc>mvDLJl5>J>1NYRT$-V|C*lKkV!bs-PSUHF5V|Ked6+moEc7 z8opDy@jb#P&pRmF+}11jf_u=(ZrjQ!W+2zGhv0W7dC9W}g^GKhU$2cUuWh1)FlpHE z#j8=gLmj8t-dm{Df^w>Iae-eLX}Zn*mW*#*%geZhj2?SeVW(@CvPI_HlOi9UQU>jq z9W(3gQ;XoZ!RYRgdo|Oc^`?!kOXDvV=vp*wK9i?C!Aq-{V-G9j94dl-_Z$lP%i!OG zw0H4lwc(o;)bBhyC4)$A@6>tbV%)iI$G7|jzHR-JbalA++ox)J^_tvSM$IL>lMI;d z3jBv3-2mt6Ywj-#U!M*5!^amb95ZN;%MH1mG4nH*EJ*FtSDlB*;TfqXXhunBuHBPu z{)T?mF@8sdc;TB#@omPMt{7S|ivhQA3CH7%RyL2QAWgR}LNPq?fn9yafa3A5$1Pqf zTlu51l2GVW=Q#lN{A=Fy4}hK@(<1`<;#;=bIBN1?kYaOORI5=+F;2_Vr{FqxT8b&Y zr_9h;Nq;=AVP!SiXOgL$4)tDdh1!RVHJ`EDLTuo3i6k-Pk8FC^+T%m;=Y(zLTWDg5 zT`_{Any2B%wVPFt+QgvlINC9q{R<`Gy3{H|+f>&51y&G?zfpT>xvI@9B3uOklhv#B z8nmS1qNM)vmLgJCxy@)E641156;drO2=|@~D?}+yhpB8E{=xG@y6xkesw;mLnlg2CVZFf|%ve7dXv80FZ1vSoE zT1H}zRNS%va(5^qygb7^#o?hEahuo7>!DtJ$(}LcKiMzfZ-@K^d0};-ua7nRxk;B% z@g>8;Ezq0+9?$?PIvgCH_0vcDFnkEN_9<|RdEsCcI&GqT|ofEF= zH+N&l_21Yp;SK))gDx$6HFx5T6J81aiKt7dnPPUveqyp=#2fm?|3_f&wx>A(w72M^Vl>udTpi=whk!QWXIuD09E;k2iR4ma1?GUlhZZdNv9NZ zPjhxAM#fsLW77j-l z^{$F_1lzWzQH%n9_-?$^v98gT1m}aAwdG~9Hy>Ql2;xkWjDhHS z)$}+31O$4XqM%61f<|{|88vMbmS2}VV48_kX%wQ9(6pHI036nYOSQugdgF?PBPBoq znD*nfUx^6nKMLcV_buIz1ch9Kk;fII3IVvWZNrQXl}Dd32OJ)1;%@U4gNE)8LtOHb z*r>-tMlh@sCya1A=BABE+;?XU&{b%h?>m$aO1OsvU|^rhu#}qE(lNe+yJsgp^yLE? zecA0&k@A8-&$T!rsYfJaden0fYdaRKp)EK-tP7j~7cAKw0Q{@!Uj*p0+J4KPDAVt> zNx!zBzZ#v4FE+z4Di;6}IXLNFoBJ~S4Tk#8-^N}buv?3lP1X_4GOOtL$6ECtk3Jq> z40v|eSF<55BAYi$fth1G5`8hne4iE7bIYdGQ?}Rn6<(WAz0ZK;_=(~DBFarZ%GXrW zwRvY|lFI7UjPgu)2&3-x=t0Ii_O533_u>w}aGHB))9LX(0eiL?PhKn8lTc^^NiChd z_06=VduyV;W2ih6xcd%28qAYXw7!q+48bQxC+8U8ob~)`;U%46VM#i4Z!gI6;f$PK zk++%U*Iy5{D0Hi5U3OWFjr-VBAR+E5^gj#dmdHu{voAdCEOT9hUPkxKOsMJyK-^H8 zyio)`VEIk}-Ck?XG0iP?^hH#}Vr8?`Hkrj|l|dQg5GM5tTNa(naMy%DwB zNUglt89rfy%|UJA4LWdDWlp)|*E7wt8D3i0&NcCST;L`6e5JF!$n+g)%kaTu!!thK z#QN81apDU|kc4Fs2v)w^BI?z8j=y*($Brj`g13 z5910{V3EnL!tchAn29?H?rWBt#p^V=M;&_}zSY}@ubRnf#|oIYyVRP~;q|y6keDMa z@9$d8@aoM#U=*D3&N!^we-yh)cFI>PjCxb9yjsU8xtWLEV0u?nYGa-Gn{4#(^zk(n z)U-EkyfLLk2oL3tP-;1RC#6X0VE`T9F(6|V!QOb9cHG_=dy3{BM~Mp;IrYtA z$*N9n#A?Kjq~@G3b!M!jbIwwXo~NQsYo@MB5JBz6D;imCVUYdCAY<^X%R_TK3<)P3 z_3KgG>60^VJBP2OC{R(Ar!yB-r*_FMFKv}mY9gHRQrV(h%gJ6&PDe__I(caTC79>s z=DNKqz=*>YU~$exbXVl3Pu+Tx?Voa`?WdILvElMKs4VOzoQ2rs^Uf=3{Uk$xrFQf! zOwzR!vzPa*cVnoocvYLHp*+e`u*og1EuzE5RYheB#(SX`DszhKwH;C$tvn=HbKHzq z63HmJEQ6f!PY$`S%!-?Fl1Et_A#B8l87tqdbJJ>f7WWP!I~O=4)sMH!8W`CIao07Q zCA_yKq;Hu)`eKR{Qj>Go+HNk^XIZD~gxi4AZ6I@l)OV^HhNnA9<_2TNbM0JH-aW0x z3Vi3Hn!dV=NopEIRT$)YR=?S*Gv`ZlSaR;rT=;_KB>ANyZ@p+~-X-(K9k&ze)#tjy z`QeH_Ks~FSw!M3MtceN7VP4!aidAWCsnDjjJ)ZjXw0o4`j<`9j2sOrz;{}LZ=bFj0 z)>dd4UvDG5X5ZgJvJj*w$6?;Fp_kh5ltL11*z|GYMf)iVzz+35-bCzVb_ck@uQ<1w zS>`GWx3H}{kF;7^jvF27zp|;*c3ZK zhaG`9u9g7GKsCS88;jBuCNt0soYI~ZQQX(rNqUJa@;$$^1!kcPRzPPNcU?RofkZQClX8#gS3l=W@S$>E5+0yelrPtE_2f zaMqFWBSnA**YK}Ehr!pHTyenKGu*`@gKm*Q^ST~{A5VJM7mvWwij9@~XmD1mO)U(a z9(%j>5t$ej`|%*bek| zNq42|S5itR^P$|4LR0~aXXfjYeFc7(cpKm*pL3~bx{-U%}JxT0Y_&?y;EEf7ZD;TZdip62ImB;T|T%FEH;AcE@ zUa6yeCcV@2okq@U>#LaW?nLu~Pb3_Ge>(Ng4ftXW2TckQRPs(oO6X(MZH&b{#U*=# zUfxxdQ~IPSS6f~E`hG@kgkd9*@Xvv?{R-+!lM0F3qi34z?`~qWw|ShZfH)?wwGCO` z?P9lX0nKu{{;7E-liTMmN6U)(Y!+QYg$Ei?vL7_3D;v|i(qq4fPHbE=b@~>C1@#d4L z>8Ngez2sqm;=XEe!{eKL?K9fLWz$gR`eWN6Pr*19OP*qX{!nnJQK zEGv%>mE&pDad%DiIAw;;u)jU;S7;R$hiVBfN&27*RT1-erf*F{{RXk(0o-d z#IFwNQzwIUIRf7#YDluVBa(19RyaAY(Yx&)=s>esg33-wH2XUgztJ!JKd)Ius_1vI z7;mg3Prn%*N4V>sYV@*9c0U1&gO%J?jd>R;T#ZiJpN8y#WZ`=CAocgAvk|wU1CgG! z?Y|uU6V33e;}o_wA84P#m(J2@7jldZnLoQH`@{KHia8!=TmlqvU%lY*P_Io+4(Xf5 zr!;Ofk>-wi^NN%{K1K>htyOY2l1Dz&auhcvyWu|OPCDJ1XyGtNKU%l;gXp!2vK_#l z1z6tS-WA#H5sa;KP@&#HAk=RgZ6}J++M6-lRdxWm3`hWGzbJ&P&uP0EQpP|W4!NrH zE@HsQ2fjL0`Fdbvj>f9VlMWjPp4HVIHD-6U%y*2K$y@?G`qdVTsm6Pp)~iNC{XFJD47GRi=qrCizGw_^WDjxtmVLBS3c?=Z{KflsaJZ_et(+ zWWqOmy)oXC$pok>NY5U|x|EV>f^NoOgXJ0ATR0&0s{$e%9D97VpdtO^amPcS=Ta<1 zK*kTDr0O!PqDK;v1_@kstFfzRa2eyR3l`7`AA5?lu^xkP0AN==Nh3y>#YG1s9mb|y zmH_a3aZ&`p!RL;-s|gV(22Kg-T=VlarkhqAy^9f=x`PXmwW<}2B5=EjZn>*SnFL@C zdz#AX#+J6ki^##jez^9n4LMW$TGP$Pm*#@q2*!D)*x6lb8nv~BltSY2X9)~rlFWF; zeYN3#*^BHx4Y$14Khkw~j7uy-h~VQm&wAvC)Dh(G@lSXfrW{X6W-Sb}yWY?EE$Gi(By&vE5o*%^EWj7bRGaM)j{~)BgZw z+v#93PSQf`Fi1_ty-8D~wMyr+hRUneS4jD8_fnQ^GI%1J_kl@Kp0$Ib-QPiMMDl#( zoMhM5T953venSX2Tb0X$Z+lS#bre!`Q}1L;A)-Z%xpu#p@|(uVnr>{kfWAd zn)PU57b7aAT5a2*)XA(hyqrsdcsx`mTW67ea&UXr7_fI@(w@8x#;8qdU~&Y5ch|NAVq`R!4iOC-_Je;Gb<(v^YGUTFd^{nQlUdeYoVUU0jh@ z+e;kp4x6#`t=_9?b$C^FHkMP7rRYsxLP$*qRwm6&$VTE^ErVDdyG zSu#N6gIHmBa;mD7UWUI_zKHf6KTx)2U|n0W$);)=)ups*K2Y3@gPQQ2J72sgO1W=Z zbo#B-_ZXGi*NXK&)wZhMPeH6CQ@oE_lfPwH5b~ULId6o#<s>s$b=}>w zE2z#hlh&{sOS`eS4oM5wt#)DR!;#0EQ%K1)cM<5e@Y)CS6t+14*DHBra{7T=Sfsc; zf~mo;O!#Zy-CM@`>Oxvoi#vW_uUh>Z_zmJDgYAQFteXX|H(mtJ13}XtX{k@n`JQ;f+I6 zxSD+$!s*=MLqIUSc@^{Th`(cx3tYuBMPqeqbDXP2*aNM8lU`j3rX_jj*0Mx_ZZh9G z=aJOc=UA#$A&71>Yvy^l%rqLaj;G~Qe#pA5rPP-CUF%w`mflMN0U?HRSpNXE+v#6K z{4V{M-$rP!b!*9Qriw8fK6D`LLHr{<2PYNwe)};QX+n92rFEKo*3w(5#>zky&0h~Z zY}92f4<4Qp7S$ddqWme-w9DvH-WdF~<%oy^c_$U@kXy&4Y3Pa-a5z=$E23DU2PbIF zWa?Ad#=y$y!0t!AeLhdZ_-qt?q*kn&keXIY?lP|>y1KD(3}g&fA8)1JEyKvIi=Chld!KsxY1YHVd+x_A467Mhe6-?$(xB5sdgi|(UEP``Su%u!=IvC_DEj}_a+7E)4M z9kGw+R3h;KyJjsRu8Ct)rtFQL5?h_1NThh45aca!>L}Su6dZ8t<`?&BiFS%K^sQp2g{7-zct|+=Ba57%VFcm=n3P! za^5TWg9KBwGTh;_>OaQ355<2F5TIyh+{@oT{d)4TbrvC|Bz9%|F^H2%qu8|#dd*^W zNjA7AJ37}RrTCWe^Tfu?%wvak12bTn@XK!*EZ62qrE$3DhQO;5_?1QImf!Cw&f?tD zrG&$%*{x5|^8OrjV`(d&aoFnzPO^-BrC5dj_G@a};tYuyf#%Bh`ML`D_eb#+)zoVw z_bjM;Zq0P5sQFhL+IC;?{vy*8`$tPw z8<D~{uioO>Sm$&ucPkIBYwI$Hhm{#dp6gS<%(D4m zrk``iGDL?xJ?X6He^ZQ7Nz|O4PXzR+$@##+99L{6`kqv^zJ%yWTxS?OW~ANETB*1K zNhD&IBm3+5*0HM6GP_59(WvJHRW|4Du6rE%R+-BvX6cS9q>7_B&V8%%Yg<#-^)uWL zDDVK!<5YI_`CApB#aNx>eHN;+=1k=6#s({OJE5eTxtz#D9GrRziI8o_C;gHt^FVXB z^XXAIAu>Mpe+uY}y@;Gr)T88$rvsl%(-th}k_bI3L?8rbImI}pM{oyhb*&VPxvpfj zxxqLX?eA2~JF*WR-nF{vwk{WLPH|P*FvlS$ar)CtV>x4hJBra{ z2M4bl=erw^I8;YxtwmGYIh< zWc<#10DITYcis|$%Ue?veq5;eSrlTWzP=H|6gLyJk;HygBEB~?;+Zt;tl9E8=RO17 zYeqRN&ZlK@b$d>h+AodUO`2I^w-*Xns^fC^{43P-%}&~X56N(m zq`p#};Erp@^@(D*@f0a&OmB1N#BWX8t;-Lpxd+K_vm%`5k>z+9A zCEdm6n{8z(O=AY~6;YSw=ef;Oi{TfCb;em*)Lh=$&;ExlGEqnKAN_jkyfNS_jXT5e zU&X1*boVg-0Hnm{h2w#dUe%%4+rg&W=G_4afzC7UUu%G<-V&4?6nAdjZ@1ijm&4pR zn)b5P!SJ`k`#X3c7Z%WORRHZ=Wct^sTX<_tjQ|LP9)hZ^_md9P1br#%smdh4ZoKne zq-)`+t2TYV)FhRoqAXl^YfqLVg^YIlmCw!KyD1}lENn-8yw<_gCnxWLOd5o$G3E@D z>s+{;W)@1rSQ*~z@DGT84(#qcJ1?06$mb&^dspPg#*YR?;oWZH0h>< zEY%bH232-fWggY}N&86N{isi65~9x8+Suwz>H1fjmSPk!&{XB4dior>zFifCl%>%h z7Fu3TvjK4#F&-4vtIOEZ)H1HXIUIMZ(?j+>8YQ}q=U!U_n&%+C)9-aJvP#5%cOt(_ zf{jMzmW#3ZYdFPnpJe&YcbozdjE)dB(oVduz=~)-rWu>*~k|_`<^fcSO zXY7{9VUQeg*QIY#E~-k7mpv*iJ0x@u92R#)0muXOs&|bO#sZOt9Fyx@;$B@}NUk4n zC#`7QSzbqGB}F6;Q^jVm{E}SHQ?1gAYg-rMv=LePs+;)0&0|{cI>VD2D(9v+tq66- zOJf5d&$y{=E)0?hWQS_8>*-oT6<0OU(N2ZaS2A^Zc4)gDyf(`}>84Xwg4M_gmE?^<@+O}vm9 z2@1pS0&CH=8!HxP@<3)EbmFj~(Bzh4pb!}3@kDb)QWyA6Z))Aujw9K>R zB+xM2yI0&+yt^5`Op}gHZQZ?`dRbVaR&YA^ta~806BzJvPXf9fXFJWSSjtrtpEEY} z#<_|xV;?Ts*LKzClgx@EwDFQEjDBvPwV35WU-f2L|}Tg36)%tFSDhw#NvYr9Fb)(ETSk=Rwz zpxi%sPjV@#HSZ&%i^WCcRgD11>@!q#OPxaQGD0@OI+0wapLh04{qx7U19ioBl50(Q zV3FHJv>r3EqOKWX>L&`%4&U0vqrfBEjk)8R z{6qLz;y2K|R}@p+EMTxI4;%wut6vU$S!JpCZUg3^Y;?_jBgQ<~e0!-SqtyMghAB|Q zV57^rKC9DpkCia^$K_qcw!Ioepx|*{A7gldIAD0}YoU)&R#gSL#bcH6VxYNE*^bGf zH+vqY-XcRGUU7_*+L(1%*>@`pkzQ;r@Eeundeepf0G6Qc{LOtGJ~NEfq>nrM4l87K z_ZqGVC9(9ZH`mrXf~_G7+?wLG9epj~c9Fm%HS@oY{wbXrIhi**V>}W76@$*>R(FA` z%PG@Kochk=#r8JV?%r~S$MFi_H7|(PQL)URWw>Eq0_tBGHH}s{?X;;p`DT-D)sT}| zR=UrNF7@VVW4w$!p;9Y}Hssb=h~n$hbs-z1c`&V#x}3FUlezc1{7ko&La93NamlS4 zFNzVs%FS~cfP20x;VX?^{=)dhd>Y>4JfVE&-m`8zTfN_WTO$Ag&MGYnMYL@W^I6sB3aHAK@VtRWdX^ye#w+T7xAAhNzK5NO$uf+#4y9## z9Tu_i^TqSeI*BDk!67q_Ip>=BKgK^2_3sdPswgMCl|++m7=9a`eT{n~K9}N~pAh(~ zQZh&3of%dbVYOhl8jZt(5;Y&(02X8DE4BE`rg$cAgMSV*XgoDxq-y$ooDFkv1c+xc z$eYR#yc`qB&r)mN%lROb@jX@2efH#-D2|%F;?B2j(^Q zRj#_$_Q;C(z~dG2Z-Kluec@aCOF5;ALeYcrHgKeW`s?Uh7^Ids&rk+3Yv84X{{U)r z8`bKMsGSvxN}_j6?;`OX+}8@NF~)mWd8O*I7y}s&Jv-*SrWjf@$OT9}am8OvW=m1` z!()p2Y8jNND>FBgUN$}2KNAS-!aHPiuNe4=;t116xp>$T6p{zyRgS*Q2O|fbYs)-) ztC!I36%g+u107FVQO#vmqKbMLQ_0jOn@7Pv6ntfPo++JDX%R#E`N|n^VEsuKPEj%CM%Xrb_((W0@EC8>qjsg{EsWqwfSbF$sNnNCO z5Z=g=p(RS=J$bIe(&U&?vI3t|Twb5y{{Rx*DrZKxR>xLemE7sx2=P>#N7?1uj*N$j z;iZAyNm#s2XGJ^0qGwTKt4SInMaTz{+Pf`3Q9rW& zO4rsqTmJyG6hALKVz6)Z%d3rUIHZu04^F)Q0EKO@g|8$)tS8-$81<&Vg0IA3qh}J6 z)ssK1XI0gcykohJ7cjsjcPq1JPLxS$aU`=N#*yM!%Wd2UJaO-e`J48!)Z^AZGI(oH zj@2!M-Wj(qgYy<$zy|yPucmab2x_*s0j6VcrNNLMIQIQ{ub93rcpt|;H2A}JeztKX zjkGCkYN|=hXb(BZsjsKuo_aHvJLr6G7GiMIisgMzl--$F?%SQ*0n($~JmO7yUGKtw z7+Jx-Z8^(r$owk-yc6OzaFXfLtK-n(zLnR9R(v0{Z)24p6(qifdYOe3azMfL>ru(KZU7mpk8L|J`3M=SQE4;WovRaI_Z6g5u`fhnF8L1C z#yjSepa&UR>tgVw{LO@gzY5Zez}M1XY?C15@sUrSG2NKDiq}V<6(nJCoYcNtn?C8= z(!C--0N*)~0Nampl;iOCQVJCLjzGyFNENEB4Y`O&{>S|S9DGKL4^|G%8)Y25Yo;+bBanVl)-k~<~zeFS4@tXH# z_-T8zJ4GlPx&c#`d+3Q?*yuuNtvqx@_a^XSKBt9Q}w(a4vM91 zj^Xt=N&xTj`tQBL$fU* zKU#)OLw4d{a6JL8Ts!SJ-`1mZDMAMBxvqI)@lw*kIN{c}Gc}e*yU4*OJo;CPYH2m+ zhyW5YM#SJ(uHHd3ts*vZN6Kr3)Vw)&8^-pSmP5%Kxf!k+`6e$EuA`y(S06fcVQOns za;dCcX!aL2m{S~!!So=WYcEG=UI&*3ONE#ea(WVSPAk)N&j9KgrKZcsAD&4ZiogE= z3fSn$`-Sp^hb$YKSgey3cqQtDOq7a}2fIpVqPNZm^Y5=QxkI#)L)VLdrbJ)RZ{@{!JbK=G7NX?F@8a(D!vt$t^G zK-OPe@lEWTnc`L|LwDrzEA0OO8u)8lxkoWH)5cq#56kObCI0{le^8#_1l-%C+;F7i zXX#&W!x=s*E!3*L56gJZI)vA-q4Q_S_xgS8`Y)Se>2!l3qhZSNUU1qJvR^=Cwwl)G zb{LV9YN_-w9gLQYL+=O@s3VS+GcuTF)zedKz$PH9J1bMn6C%1sgj5OXFETAn>)RhGm>6fWuqWi|Rk zs(#B*-dvde&mPcn7$5$%XD95*aipm+LS1_O%<=hFw6h4-isy~x=5$I^Z+@xhJ^EvP9>SR|ol4)L*lGi$f5a+~jkO zool*MjGC6-Mr#)7+m}P&nC%X;aI0?-+IZX(72jz70=YO5+fL-;e&f&KUw3Ffv-Opl zC>GcOvOtfYlpdZe-l?BaauFp1gD^FB> z4L^jn2yH)g1LW{V+UKS4p0eNtibY2Lfh#E`yi@OyE`@~Ge8R4NG;!*J+G zuG$lwHL;yKbs;Wh&&q9c!Wxto<-W%&l73ON^{xRt19_-wBu`-~9P^QmYxW-F;T@I0 zK6Sd6J%aT2=~QC)BWd=X!qE@aGEcpCP_H}Q%OTo?qtTt=v~bwqn(^6u zA>vz2b=EyLa07g-6xZ(Q_$>_9?u}}#*e{n@S04d1)*!v2y z_&KM*R4uAs6QdWu~gCn?xiIyE9!9tBU1%4dNv9KNjr&0A|fb zdBK_|mAm9|UZbS`&$HXuB!6Ib$D-Hj#6J#n$dv82Py6Dwpzt=Hh^ir6?8?*4tm$8u8_O3 z%16?sIwWoPmAY4T9s`P6F-wiA-(%-JYfZYE+C>}iLFhBqyl+|fZ++rKn$m5;(f;_^ z$^2{W>HI$rKPdcaf$;nriAeBqgN`fH!ti`(yPiH_#TBtC(%ASm+u#j`im3Wkp@vWk z867tG+ zT0MmRHJLwytO^~lMhWLTb6gcTIyEQE&$7#S+ZBVPsi$M)82Ea_lFim!0crt_}r*C;}@8Ghk&;F^`ckFB5QO>Vd2iRgr-Oy|ROF`B+GoRG4-;RB(rr##iKT8> z$a9XIeJkq?Ch|3~j1r@a^IB7UIJdBN@?pU1gYIN6smK< zSs$%r+)+YwR41j4d!1q^pd`3C?b^6o?-U|juq7}noYhVK;uN`D_BDt!d)u%U08;*!Cl1v0C-m|W8pi&a2sTV6N>gf4R~JR z3YS7KGtPah>iAzFuPWD>^V$CZ6ye-$OLGTK_*ti3N+y=p7bn$gv$Xh0q@hL@Hoy)T zl&@IQ^rDvWfskvlipOfG8_35zSM8K?s&R@;{KCF#T2kEb*uE6#(J$_;VO}}do$68W z*1|Fy$X-3M{VU$m&35pOjMP(G0GR-eaf4d_0A^5o#N~L}-^_TDcnZZp1`PM&pZ@>| zTnivkZi9{nKl;_}3u(tZRQ~|k=uUE{j@8jiETwOT#!|%8d$Y#l@T^EqVNwXk`QoJi z0EBESF36V)Uaa;QV~%<3DHg+XWQ=`9O!Dec-X?COpHs{u(p6mM4*i8}+vu^m`Jo=% zS8Cd5Q<2uJMP>wi@@W;~#dk7vY+DXAtw8{{WsV>+63C#*u)~Q zpAK7=IftBMBEABqFA(2jSth!l9jC($?hD$LJ-DsgKZdbFz>9VSbN6fNsPq^k7~9QU zhewZb!h`NbRBBh6+{#Z)S@XrGfMXGl+?5`sD`wxoafx{WaDTgjUhH)2AW)=Z&{cQS z@VkJMK9#jBHA!!C6rztMUk2GI$p{EM@l&4+>B@u*1CL7d3#&q_oNeR1b92V)HbEOe zuS%X3Qk2TGDwMJz}e?Nq$}q>egQJg`!Wvl^u|TaQQ5*}xG1 zr=BX@dTyNpkg<{v(A02B3}_c_>eX0UL_aPLIIO3Ea*eEAH#H+QS_tOb7}!T0IIfDp z%SfmRJo;7(Sjpy(mz?rzsnV^=%NPoM>xzdAsnl8?-}aqo!pWT!R;AEqCaxJ;nMg~&n)W@_Ggwiht>XHn>~6_Z{fRJX-vi?c?sum$gf)( zZV3iFuo>x59WyF(7#@|;43>;mkvxj{nbn=<&p830U8xXEayATBb<*5Uq%x8ZBE2SE zEO~?XVErno(vZL1AXLvKq}8pVROJ}#d6ZfiYmiw;C!UqFABX;2^cCn4>FR_9QJ;F! zOFXFgKOtBCuF#VBPRd!mYI{iYl+nVj&OqytQm%@pff+vduR?1zSqA9Fap^&~0dT9d z{VHDy;dgLHXZpimZez|R(S{W~ybSY^RA%t%62WopUa|I7VgXU^NT_79k8#?+omcv^ zhFYj1XP#G@w=v{t;bdhY)ff@T^`}SRn=RQE>Iv?nr?q;Q*-D&*81$*(gtKrlT~zX_ zanVHbt5)ZCZ1WM|+g#wp2p`@QT$Q^#Q=*I~iY=TneN0vq5 zxMCmbkeqr|mhk*-8tse>4sbZHK>Hv=k&pNlO&zM|oPHF2ULB0pKIfFl;pE6BH{H;2 z#ap$|)+rdW0RghRk&!7ROxIJHbWEV?|A*a}j9~JYb@n0gjZ7qQ-Iz zeEN}H+%{ma=b*<*m8_A52{^6R6KFL-$!h#pOjS1XpAsGIrOV^;?~BH zif5Rvkderw4ZL<0xoM{%;{zwJ6~8sABNf~8XSGWNA~(q#dsbAaB+TkU+ZgSprz#^> z1HNjMns8i=xE<@V@_~K>b4-%d2#G&8HQ)7e7KaXW;n6_b?kdbWdItw?Pkh%(U_vv4 zk8w(oqDj*{(w-eyWXaUI1dkW8MB><2LkJQeG*?_!-HLL=#s^%TB@$ld1kkK%L0$)^ zHAC#_CUJrFu9kS#L7lu}vsMkRay#*gnbJu+7GYdyu*xyDPDg6s^`8mC@JY2Y0OyMK zWsDR!2B_Xzq?V)=IX!E~#$kP|EXNr*?9Y?0d>IhDCu8H-d)Ahl;OMdykmEdYUd4N+ zubRgkgH|-_3`vr!!R|S)kEg@5)qZOlyi~fgjU%oWJs z3YFaK%5dKODit892WxZ5sf{aK8$h#R_#ljDiqnFBF_i8D>sajx+{H!)D&?YKmmuyn zg-GgXn%wH(<{^y!6=GBmXxx1&t+w#1^6{F|kdL$SJL0i)?zJxHx+K&p2B-7-XpHRPJJx z6so0qQ)uKLkzXFPzwnQlutFcku*79ClhGd9oj9Y#=eE0Z(wi2acG3XRoL9L;;Zbx`J<-94#m8$NJ7c2G8FLnLbDHez^f?(uQR~(%JT8h<~nM=6SX9$idUr;VqE9h^4DC(^nr9}ftfOGT64*1bwCEC$4jx6t>gg@lOt zMU1bhu9#pU6|kX*ayg5AHaOKt`D<}3@}nmtiqTs@P;jMz>CIh^9k|Hn&{na+$6{(( ztFnSwE)*{W4s%)yWCUbRm zXgs}g25SoH)NuKD8i> zDg`*m^s6e^A((gVO(T4VZ4R33IWiTDXQ$;>!~>6)Ii@PGV}iA4N$b=P&a;&jB3=3z znuVAw82r3;^sJ?~RdyI8de>8SH{0&ocVoR{1S;n^=D6zNz2G)9*vmkpfCX!{y1L{H z9CZ~-P9w_4deuA%=%+{Bu$K2RrncS50OQcp5fymazO>IDm?{5wN_Tc zc~N~$T~5VT01`k1)GHotc)$d6S7a%iZO0vjLNE`$YGX~`V&zpNSyd`Rt~2XXF!@0} zaZ$&~4V=`(Zotks>S@)dZIPWOnO|@3dt)69NQ)}ANCk7+o#l|hvNK9aZ{j1{wKzjf zQB@iyUPvGuRODiyOogQmN}Pf@tv!M!H4-b#gw42On2a|7KOEEMka8 z_DM*IGg(e^>qza!IH;nKGVp1VK3f3Sa%$EkF&wFj1A|d90YZfbjFVAI&IWn*sQl2m zT=vCGmG%|cX`CcR}&G>9chknl_#2}@)c}zp0xQdp)X@y zTQ9id6$Q+gI2Z#NHAqjD7!5>@NFbio5~CI;Jq!!P^DhrLJ+W5pV=J}01IY_MeR6jfI{x^}9sa70|6%BnTN2f43GoNTRO^CtCXp5_a; zE1!BmUwJLh(z68HpE)_lN}ODhhmnfCQygZA8gjE>;i_M>gAoBuWjp@!JeqpQG1Sz_ zXh$};G?9dzP7Oyin<6`U`qdLFZrZ0GT5Gu{1oo`tp%r#(7j#O_N`k~>jMGc}!w0oh zIVYC%){s6E1k^8qE`7UFRb9gIHG@XTaKv$n zw+7WJa&ziyok?){&l#-AVeGtN8u*DDS7SP;N4 z;}xd2B0yBOc*(^@NhP8x`VDyrlNliQrs7ZUezg!{^5+MGQttl%Wxp!qZHnz0sbLyK z4jPy2asL1b`qspO7mj*#sB!_o82VSY3Q8+uH$6%#WTiUuRPHUd^U342Zz`4<6-wb- zW--9z`qxb;^D@+q8&QNRxnt6}yP^bV>s{uqprPtX?OYwqOeQ(T&^lMEhouD1Lk`MI z7UBu%SC+{RK3tz_Y%7pHQ^~E^qr#4Zy>>cjqtJx98LML%U9Ix>#b1iaIO8CHbXJ1K zGm;e6ga|TzP%}x;R=KN{_bFRx%jO0>GhH>Ulqi`{cW1b!!4Ua#kHWPOC?g-0a?YCS za?X=_j*i|HIVw-#QW(=eDx7^O;gyi$o0eF~Cydl8NgQ*eg!1Df45pY+FeDBK7^m*Z z1m~J)dKrV^rLR{sJ>y`bYmYYoFd&j^Zo=bv8?)B6r$xO_HxZ_%WgCLHIL~TF+FzcS?NCO*fWY7ZO3lV| z#W_*3Jf|{Xz^`0=X@r5_KT5B?eM=u|Ln4Ly*r-%nWcx;m8G#w*o8}HVBZ{Rwr)E^- zRZ~0qrt860`%T$gm(-TvUg{-DU)+<=WtwmR7yPoJDP$+ zx34+oth0^iMsgQ5kqn>_z1Kd~ePts&1|Id2(TtL5nULU(-=$OUH(B;l0jc1NXEFV7^@a`z2Q2^~vka`dQtz#6Hv>YQMc>rl1EPDsbnr9)9&n&~(l zGmiCPXAS+}D-mV^Mo(I>mjMnjxE^y(QB4Be*AuIZaxv31-RE|5SzGrKOE2L{ZVARt z0IXCRklQv^QMhsiB)1z6T#RwRH7J;d`2U`O3F7Se$T;j##*{?G}?II1(xx?Hir$4agwOzz7QSk5nE`WtCC%1(LCIi@oMDQtomOHr3vOh`7C$E7>Y%MLJWC+$DQnvC9IzV<7kijrE2=;_i_S5im^ z6*9^lkIkG6=QYS1;v1-Hnmt1xg(oEA0=id3v^ti#=I%cO5 zhU1)?=azgq%XiLd^mBsQ*H}d(~N=B$1qxOC+eyc_SkSHBiW# za1R64u%T%^Nt$VBK1t7$--@a(26qgT+*DG^0m|n!M7ac&ARl_}YeN-#nug#3@|-d2 znvhOBtmo@kerlNyCyq@?=8~X>!1Sh4iKq5}N&DZGD$1^UkbUbFr%>4B)R5eM@Ze|b zSl7QPNi@y1ZKolD{Ay5JX6*4;{&&h-r#w@|*~rN%J?qSr+cmner{)ZEnr89X)iHFt zc*A?tFF0v{-=5CA#P z(x*lRMSVJpxtop25kMU(31eR^o1yeIKH?XQel5hBWqDnv*Z^FCWdmfxFx*ChLj-su^vKasih3}fkNr^c-Kp&l5j^PS{wV3Cr zIH#?FRM%5-E&KK^G1rq;m7GhFpF>ojVS%wvJes_%gV-GRtSWR?IvrS|(w@1=rv}K! zPJ7jFGzUEh9+Y{>w3gkR@qt|PjgjY9sJa&&fmHyFqm%1d^GtGhIqk=49%UTl^y0H+ znTzLx>0HuwIAD{RZ_Q%BoP&Q6Iyz^ua|##sJT=;i_X@mx}D>62EubdpH`jMGaW zEROl8a@j0tq0ZLNtvIyN=egcQ69N|`5^;*emNhOwQ}3GFl0%cb2aYjRWWz3UGv1Vr znpG@gh}ARPb*l18!AKu>t!X@Qma4KM?H~i3)lyoWPO@fJ^S{4Z*RY!aaz+}nOj}=^ z0&3K2u#Q*P0=ppk8cw2U>>{}Zcqcfie9*%MjzHi$m zWX97pT5K=_CyvzQm9w0%9{npb&mlfup7cj`ylpLxdQ)*kx3V^p2i;mv}(aQUvrw*H$S>lf)9G-qnG9brCw{Dv4A<_y+e+KIcjW~_s8-&_2#2#U#T^W zZx?3b!4IIQP3dFzuqqqWu5)0`l1a}TR4*wfgO9Ccy~_@S9MlHwgMqvp`gW#W(l*}b zY<*69(6@Mp49AMWl6EhG+4@rbpa`+Y<3oB1>6__zxZ#gp^*Fl)xgn2XT&LQ0zij(e zl)44FW879!upKbCI|%?QR1(PT17zgZT1>>`F(clrJmE&tdWy}ow;J5bna=aU3!V~V*esbijdj8zFFRc!Y(Ijdggv#E7sS}TVcM$w8>*f zc=-Bq?H|I*9UObFYVw0yQOn{oKSu1CR4@4wq*@Ykw7^8-sH~j$DuUd2Y&0bD)o*>R zke6*PrL=Z9@6}ah;POEQ;@WI+EG-mF<&~Y`ftszL8deH2=;$n()iXaDgakVQW4 z+>$dg)!?g#*9X!)ijd{E-b9dW)R0l0h0YP!QZ@99&imQoaqk?4P9tU{vLfE*;weKl z$CndNQ3p6y}IB(>CMqcdo} zNvma;tYjsE*FYLFsx0D4iG0E^P57X!jk#@&IJ-uVDWbl(8eM#uQy;jm=Ge8|1Yare zxdEMH%|(yS%>;*#>yCk5*#1eyjyGZ|Bj&aln{ki;nAG9Q$z3%s&ysMdvEo*d<0h96 z&vKBFy~v6C;Tgud%xzn@r9fNsO))^_r96gIiUF(P^pBp64mWI2V)}+q+8=RA)d?%J z;~b!3vmA=!hS4k4B1YMwD2Y-34O^sdk#GaGC-XvgJU6ofag)C)9o|6}{$2U;9|@^L zG=czpvGbZL6&93`Amw@dFh#7wRN6-6)Ai=om}Nf-JgWc!+b#t8=+^e z$KT$iwCghgoo4RX{@)&13a#Jw?3ebUIJtsjW)uvg#viwv6MXf9T?+k6#|gTc49C3) zMP>q;*-_@~b4#r;#z8j?<+Lc8tTA>uJaWg}DN_1Nb#yl(MXgP+>L$4>_B%qvs0;;p z6ngcM_x)Xvt$CkeM0lkjXBTU+JN>WRS=!Af zr=sxkgS5-;{@L9YBkM&}(cl!e`V|}4) z&cne6@Z{ZUm8#~snjy8AY4w?A3?!(lB5#@6lU!&zFYs*+h0K50LMs~5Vz6{|&xGZ9 zDAw>{&0bI0p)XxX!oMc69XnXb zjvvTBBLBK%Gj2(7$8-7f*ynpL3*^-qcGR95jLu^gg%wuKz&@?nsC8 zDUDZxx`U*Jh9KcLTxerTWb(H0e!41J$@HB!WDu7WfO$C|H5B5sWfJWW(l4vEX`k?t z<4+H^NNQ}!K$@@jb|9N=1KP&omnv>ISxt+bXh~98(^0_=_yvE80XxTx)iO{5+R@V} zth11L-We??0L`S=Tx?!0&V&f9cC-j~s_io}jb2Pp9zvyLS$K{NlM-^ux zfQ0>~>&+qITI_{Yrf;8VpyIW8`|K~=4zHaMjl0Nz`d1#G_PnZb8vI7;^Rtx!-ASce zyY*xg?rihuwv(z^HaG~LWm;uquEBK>n+wSv%&J5P;^nC49d$%|$wZtA#`3_VdC=?G? zyq$d`eYdI9K<<#}H)&Hl#Y>PAyBOj3X}6z%*A;xrYHBR+#ne2th}vOU*JEa!k*H!>!MLMFsW( zRZ6Elcy8dDyw0m(uxsYaFo=h_!O;rnYsCjmDNC39;fUBK)DEn-@7t59u6xfCX^t6k z=8B)f(kyi+Wct65({zA7W#>(}$KRPHQ$z>@+|59kkgvB#z?|!+)#cygDkrGfu;QqT zUW{}n%xJ@f=I5K%w@apSv_ACog!BiMc#Uj-0y0W8%({Z@R!`NIv`P&ursio8vk+sdTuLPV$t@&xEnWcHRrNxvk^^siD)tu^wb|B zzaC{}Oe}axW}ph>r11CM&+{;_?#(w@6#L*ZT*hq^>_30Z!1WTN)p$#AViUhHP?(ell2AFpUNGNh|w zEB&&I2xG2pX#PtqWoGNpM22=sR$&N11-%N{OEqN>m1v*b*p{zsqeW&6F$%8mM5OXP zD^*`%&!1C9g;ZF;YQdq?8s%CYv;s9%BzoloGG|u}mb?@UkWNV?r#Ajb#a8x)iqxSt zou$0rkL`wD^<&dsj=)!~oaMdL7e)1Gn6*WVAMy@m>h7FW7`O9eR+5bD#nx|(n7~89 z(K@9{$E`EszH;bGx?w^dIaZ6)c z_ckQ=xF}WfZ@1I*cTy1PzY$Fe*BP4zAH@w|$f#8zMNOrgO}E3>A`&6<*rwRmAPju0 zRbF4dD1}EomXN@IR$q4-Y3=p_8Ix}`UwebL{5z>|=aw`-`H*NIq$X{@J$6`ed*{FY zS^aIQubj(6R9jXCjFMzRm~0dSJMWgiUpbq%)ErF?6!Ti;;cgoL zUce$2G|Z24*ax`E&2=v8CLENvYDGPwDg zJ~ubC9M;;g6&&qw*I!ONHcHX+efDMqJ@#8f`Qu17NWfJC_`%yx?YC3_(NnhJhEZpz zcenHst+S?5-Un$u8)A)D?8)+i0av@o>diV$zS3j%nXM9QZ#<#grkw*cATjh4g1*ZC z4rNXHEH9`Z?MXs){pRc!wY2azKpL~N;-MR4P3kXAQ4d=NKJ#HGq3JQ_V>Ya%%R;0_V-o$Dg~ ze}H=Hfv2Z|xTLj$Z>mq~WS=j+N6?7usO@cdUC$$6|Hcwig263KD2;99+uxC#CbO5_ z!VU^&2tLhnC0%yc@1Q(%iirw*v7mjTG;k;W7Vk*GK_)y+Uw20Bs8PiIM6#@$>GrCR z&l9*_n-4qoAi{3qpn3S4pp@jUvC1 zVWWDaK%FK9W&+FTQK>2WCgr4JGcufc@>#|)XVg_>BDOf-AxY9eEHEYNVokpUK{+wfFKACGNC z2=IA@m3d7n8v%d}ECWOi3|@9;UASMgglRl|e&xMgJ7VwJ4R!WQabahw6Lr(m8{2-6 zG1y3M=9UX)p}Vlvjf<{ zO3BI;@fG#`d+@;d42!*JykgPsIspgla7@RERpfTB4;-%XZB1jRTDwtd$b+1p+}qBU zIHS`pyYgkN#wDElD_oWK3442A&_?!K1X9@Lkv#=iVD4>EiJ3~5trBaCFo=^}`(?jD zJon}Jg+K>(^)Yd-$f}1u>Em07yXNtz(DqkG?0wqj@u>HuI%WW^Bf`he@nlJf<4RET z!y8=s$J@3%M>QZXpLSFG@w=!k|MsQzK%9LLDI}wmpxauw24Eim=d15l>Id5u98T6= zzF}Tv5wG*14pX2qWzZb4m;yC(+ZaY4Ck*^`KijL za*wS_Ja#{ablD0u+8)qdE-20av*XWp-Z_}6#!Fiw_CQ%u7}9aQhNu{f7QcO(fgQqF zEuZ}pR#{Q;MWrsv?I+ROA#3A&SsvK!;Pk(f&Pu;M0E&s55+ODjiiE%9W``nfAl`u> z3x{CbkMQYr)d)qJzbP&|z#crsE;dM4dNKoz3D&&a|3@1Z8bSWItCk{{;n=RJj0*B> zF}G7M2e9KpoNpnlr{01Y3gLGuDgbPo&N5HvVKBY+Z7tZx;oYv{W1X;%@WvH(528V| zKK#N@hrE2_S2m~_5%7Bff&{Wi2Zi0jJGoJ@E9aA1Slf@`Wf_HU{wp+rT!>zK#pt)g zOZ=h*h-kU5t&(RbH(CiR8IV<-*7{QB1n_HWnfjLo#V9$)2Z%RAAT17NQu*;#+b+MH ziN}Sp(r=+({7xB=;t2EG?^skAI@deCc#T!o#N=zg4O@RdxKlfOw%J4vZ`cHF)?3MR z_5LaSz0wP}qt)T|KY(-Uh@A8im;obxpcWO;wu;Eto=dmGe|tS84c`mfe=MO1^&g#= zJh+vAKSbrx*g;~>x3!nH%`Kv8ldD3xjM@jE(o?2P*BQr8E<7l{ll9GyJECm+&C#rh z1Ps*F9icE?9~3xwiL;;L+!He?YiQuViLQ*!9ADFZ9Px2GFzQ)T=M##khe|!-dgw9zH zTx;L@w9u7YNx>Az$vC9Kq8zhV!u|&ckW&-u4svJRF)XCn#npG|xzz2p<9|#!7c&*m9E6l~RU*h0$xtgYVcu z5n5$=R-$nn>5h}cS3-nYg`=5%iNa`{KYv9xKW0Sk<&`A);?PrgbA8Cyqe;rSOUFDF zl8q@ln%Rn|f-K;SvDGV#bfa9xWgN2e)0HzTj~Ug|nHBe-PH6uH&u2SPoCct9Fq~$x z{?M3@1`}>`rAWWqG1pA`)HX1H-?@IEo^ox$_Wf_;5l!4m&aulY8|9c8y+DJnPG;gL ztovJ~;X*hTT7K8Gidv+1l=`#^OR4Y#wGV*+f$X4iPw@BQ0J>t?NG{V>6p!-iqo2Gshx`!T1>~TVYmIgbM|Fl%=AHvHB5w0kr5uyRmkv;VVUr*i)wW8yuB+lezR%W=IZAk5#(DX&H!pN20O2+KzQ^Z1zcxPpzUi z1ETZlzWt>Z-dFOPzSuR~{1jFLt8=4W;cEY~XO-dci?UHxj8%r&m&`wZ!d41`p5EWx zwyAiebmu*yzLofS=^d6{OaIeeQ5aK?+jGl5V;EScuQYQ|8MR2Ej%`W`dv}YQ`X3ZPz;vt3vbP=w?QGg0o@ym`&3it6IB37H1w`(h28hKx4~ax7-fTIL$X- z#IKoRGWwt-IwuPM{=#lh$$*oApBg24{PML)&WG@6`^MEK;N+0ZYqB@{jIP6b(~sE_ z8=#yIe~3mv`gG{=wMkz(`(Y({FO9(Ynjs>D(RimXQ6s#G=?&}p@W>WBJB{6Z-JxYW z0lx1lyc@?aAYfsR+9OCy;ePYJu1O7ymkJJZpKwXb<){ z$c^j}Cp}g|E?=@SYDcwfmys(+R)6b@4Uwad%j?{fa+7<03uIC9{t_v{lJiB{aia?H z(GH*=;!O2+tag;*akI^W1GGZVCB7%#;7cdAW$TnI^_eGYxwq3hgwjKhB@w_2V|Ip$cL$2}7t=2bE9_ZmeE6|1 zj1H@mQHpz(r^_E=Pn~bHP=#(=IGnl1J0ibv)$xX8_SIy^y2*uL(Ye~8XD>rkX-|q* zKbh7(4tveM&wVE;cgpV(LN>+k80s_sH<(y?0{yRQ7A%;SykKxx4X$hFcqkmQg$Pp| zq4p$DJgv&9wG{Ia%5URP2TmjSlpjeV_0;&E@iNBMbJ z;k8rG=lK#+O{bH7HeEZSGm}=!Px9yRdaq)HW&vxhQ=b}@s<+`@my`AepxToxQjEy& zzW1hm=~Z6QO$(TBt4a;222L}Yn>G2Alr{(1UxjbkL|^Ms;eU@>E?ttP#o%T(CRHBo z6sgY<%C_X%XO$`K$a??xUbpmE)Ap(L*0htb5!5t!4s4%Un9u57C+zc_#i=)2;X9(R z>#MSJ>`P5M;CqiK!>acptEj&#E3WGa1m6qQwkXmqK_$1g{uAniwH1*!KEDr-fmZEF zc%7T53blf_bU_iL2b&RnY!6w#uM>ayL+;?K&TEd_YGcU?U=8Pkf{SS}Q-DGfckGwGHx#O+#oj|2{yFauB{^wB+OU+o)eZdE|cPf9qxDYK_ z>NKK}(Ggz3qu3jiQ**s$-0G>1haTxx0bn&usnX<7v+mwZPEHHTPW*AP+F7WIap3n) z8uP>C7KuPvz%em8E4M_??v1K3kD}wtZHjY-XnSk0fMAt}39|aMPMqYS(D}vqNNLIE zj$K9Ml1KL_cPd>70{ZiMrCC9mDloaiD%9g1zIr6n<15^mJqnIHLqUCIb%2irQrV)atGZWzBPwMh1c$@iwC4M7}nC z^3xEwe%nKc4!Pp9n+&|b8RxI6M3|;TRvqKwbRt+LRjUFX;Ia?-Wiyw4%t7ycriMXB z2c(~nb=NNNNL#5)@l4Hean)NJtX~nF%E|dEk>-Z{GLER%L31+$ zk-~ph3&@qf-&E&2s`Rgr6Uyoal6&|gN@GcL#v>~ND0o=8dG4HMxrSF8?I#__wEkPU znkd1*`*&*kMtMa4vi(4oU$ju05TZ(lg*%69H}CFW{2I3l_1}k|3Q0&cfR_)mbHb}v zomDJ^D8p(=opyfMyPHBO`nH`FcLY>0>5fOtQ{Ch}=SQqbY^ud!B|@rsFY(@au zEQ}SZJGqKOU+K+eW`r!XTg7}-HQpYBoyT~Yw5N2*P0$myBtlXSRa$LS1$21nkM|l^ z*RLi!A=YFU1;=r|UN`ZRQ{=+ktboE5)+Og-D+6kR+g)&dx|g9HUg;G0y$Hvo-Y=#f zYP(|$Gn@R;gM7Xh3DLQB9?LAd%LTVUAHZ_LQ;fFaVhCn zoaLg(9-K0tH^eShexo^^+##veNw98Jd-Sbn3L>WQ`v6Q5C~4xr&EP6WG=8LSI)65c zt0MR7kwOyI)iMjd9h|Pdi#7&bm?vG!iYG`HOm%c37k>8l2D-SCJ2+W%_S)v`mi(NY zN)U52I?=50-1Fpa-N4Gi9Y8I>QtwrXUG`tcol!~L^pDDw1G(&9f(6^2#%7O4uh;r~ zQVg#Ty}0nELGha@i%Q1NY_fae<@~DVBt1fNy`MSgL2g+t_ST4P5yMRkJqj6 zT7CC!2MPQb0380BD2e3h`;`xT>lw%@BYztFzPw? zawK6`@P=TC9^@jK*O7AzinyfH;Sg^^c>0-CCpc+yX0b2$WKyo|>@3Y?soqE0uY+a@DgUIQ8LTp$*uX7XB``l>%aAtI(qj&qWyoh(;W37wyQL{6m`91Tk#v|-r7z&uPeKlz4kQz04B{Ny#G0msN41tj> zqd|Z(6ShglN1mW;yaT9m7-@&dfr?-RwLR@bYYKca~emfwtmiiZ( z1d}EY#WcRQO|sSKthY?Hp3=>*gjNjh?2T)1+=5hPO|j6<*@FNP`pn2QdR0LXRUn{Q zI}dkDWu>_FA|0aNobP>ou*#|r`HyZ=a6FPJh@95RHzw&f45Kct%=^B~nKTzgJ-}Sk z$$Y+N=RK*)8-GiCZCB}8bnurf-}Y5s(GIZrR;0kb4qGIkFRBlzZQHxP*6CphKO(BT zHeJ;)SWdU4M6x~VK3*o7?+}Jyd5si=*z7-M=m@8Occ_I(v1qJ$@aH8?`?&!zlx_0e z%2s5v?(%1uM$gNhV;KjR&a?&t+2*VHCcPm6?hbj$cV)izb4;$`p19NGTqWU_iRmLn^4qC37yX;yp3m?MEAN|8C3j6yd53*BPC0u zS!(Ef4uu=6`r7o07^Llt&cp9e)Kb;L(&M1q*9Sz2#j{20qAe+r1j&{syMma45XamW z2dKDcpQ1(7j_#% zxl^K<>*m72q#7z(n8pjXqY5AScxLO(;uSs{N`ihkj+l0@)e>h!&SVF&#OgD`uzwOp zSDpK_chH3~0POQ!z-ol8Qw0wm6|F-$7e_zE=@4@S+6iET|Cxc@R_oYvs$2RRw>Xn@ zX?=3JILwmZo;-rG_ia<{)0Y)yF(L;^3lHNmgQIO>o4GX)gtz>q)F0nOehZ8(KGDw* zu+$?LyF70N&gjiN_(;)FvtgNg+odzq?&7`lU?W-5Cu)1JA`A!!jJ`s7-A!q}uzx`H zbIzDCX-;Sk$6G{P51yQQDMDtK2A9w^rWVpuEc`{S2PAg%5-W$7@1FKyw1=Wvb4>iT zj0al{@9YkYmbfKuzKG+xYH^5W@;||YP_0YvE=%w5^02+$akZMdaH&PicJZNue0$6k zq}mC-a}%}cl&TR462oJu8BglHb|9$h%JfTo=}ww&EmT#V zUP+2)B}o0=9Xh*6CSn5y?=N7t&vdRrsQNQ<=(h?O$1_jvgxTN^%B!L>q9nPQ#3=>- z6GiIwo0t1JTzhsftIK=7;Ece|fD37s(O2kP?2=+~DeZUXLXtGHgX_XabjJVUsFMz&PzFdhPc0_Ej)o6+M;Oxb|u|I!tJ|^3MfK z!o+m3(Y1kr&83DC>-YP9% zyPi#4fBXp18~QamUTvx5-&jy|*ZG&y7^C@T^We-Tv5adoVBL!4IKUQS@R0A@XzOr) zU{2Lv|KoFYhYW5o<8qTM(Gm`vnOQFHb+Mi9@*|ATxfb5a)!I(lZD=iy;Es5jwQ}_K zo03U~q|g_?h%Yz$G@oW2+;W2H$d201RNZhhM5XsSYx;04wk{;m753upp47||h}HE$ zHDQwRi0m-0DdIiZY~On~8a|sHAM^YEDBoK#gh{X(K(s@ld6`%ajXefi9F%Zo7#SUm zka4QAbh5|1-bk)iYx&32!Z&{KLMtO#a7sP1jLJ%`$SP2?6snnjKZ+<*f*PsdmT}Fu zdyDq!4>aDhew|_f0#4tJ;5~bxAG$S$2?2zp_j+sPO}wxR1Fw24q*$`Q+q8N8EMnq} zQ%&nPVciJ4`YWou+C=Jom;w?fT-tI45qW1B7h(lHF_NO4bKJLx>a>~4g)TX)Q^Zs( z^q9JM(W2^q6K9&%SuWohE5m_N2$5H`QT1H<0KFiqxJip0{X1zhSrzo*$Os;ksCiyx zBEeYkJDFoY#z8~zG%$|ErSav~(#t}c0C(Vrz9!Ll z&n~7z_)xmtW3_5*(gO2a{{+wR_-N0DSdtdLD@+7e8;)kCC#CMpaYhKS@_5d`GAI%0$xt09sO$Ga^BHlI+lv z3NDswEe^nrkM1)gbNkH1QTA82ohICZY{Y(wy?n?=>j_@wN9s(+xFKmQjV7~PPW5e9 z0Cb&kOAjEnITX>Ntmz?RbHm)zy92q3@&n;6<*sibu zqRHy5WO$NIr=h;yA+@sDj0LL3P9`p&L}mOc!vy6ne0usr$}h9de+}>KJa-@&fM38 ztfyfXGm~osrAam}cr`B1(SW29XutQ!?xM~Vk0S3f12f((>zpI?{<8uz$ir1%%%DW` z^;)17WV0Y^Xdv`G@9sd^nICdBS$$eZRe1BzE9CI~&HK$GI`n7<2r9B{*iZzuP-PJI z>}}|(WV<`uwa-|B&U&ERRU*7&&t&7o{|Ar}lT`~LX-Pcab~FsBUlTxC<Y{PGw{x4{!A_J1vvRuQiN^U#`FMlDMh?CsR zmQU;a+;&ugoX?2x1lnJ2+2V3cnQGTg>TZ0ioi+I^Ci5x2UFH*VxAg}F+{c#&$27Cq z^8I1MV8-)JN|Vg)5TXWNTio%AP=DSBu(=acAeV2}PPI&HCRR07L5bgl1N zcK_gBZGnrc zz_60g0+ruo6R%I(3oB$nKW3FRB?+i@Z^Ofi8x6tsBPDoOGDl(HdPV!dLfkCW82s{x zCE|5t=w2~VQk$tp#>@bV(I*!+0-#IRMIJU!1?_PD4-i=6%*@q1%cW=IFG!L;_J@`O z2^%RWyU7T2Hp>_gQ_()ih=@+Gn&RWHr9dk%Et9G}T(?Yr;e<5iw#Q1xwIdZLO@`bH z{%#W|Nb)S#H)oW*CYkP)zU`9j{N{2e$frF@`rLHsPIydKY59|^AvTJwWuc9yC<|~B zlEg$jzSm(7%3{xub9CKx6Gc17Rr`3})1ggeZ(?Cm&A-N_MsG!4>5kGw@(>=Ln_Xf<&<{eZ8l?dR})m~WPIYj*GUYyC9(@+!&GL@7`piV7xnzg?U>7%j2R zUJjS|E9d{H)3wU{bgrYXR_6{Zx#M2v(~w@)>zg+cWS6+jhiOQm=&m=~JZhXsPDyiZ z%216eCHiO<8<&4mn8Xl8)qIPX3G)#xY4kt!ubQzV>4OTTX(bSr3RunqKb%SpyQB3wn?T zsX|fbD?L5vc(o+L2Gdxqo~P-&x@M?=JJie4B8xw;>23m#fO;N7*#GVxFbWZv0!uA1 zPFc*@IFvft5KNJZ37IYw>yU~PjoX7Sz#COv*umFFB4h*?NXzpu@N>KBWaS8-?4@=JA0p;3^l!k=-);+#IK2b{nS_1Hk-4WB?jH99A8&S zg#44mGoIhzIf+Kk$m3&8Yl|n6OPU|}*SzKUkQPO8W>CAMUhJ(xIh|5Ag88oYSQWp# zG@*HSm~xHGvT?cNL3G#^TAwOA%T;2aHQ-^PlG=y+)~T4-(H#5kyV178hvxY^2??z6 z>OB=78lEGB`lzQ9_hk0h%*78)Lc3wg7A*8SQkC1k4dY7y@iM-G1bCbDNMWVRoE$)y zpu3sNWqctwVbkv8M1f}3zc9lnnpc>Fmq$HzIgy`+akMCJOgM@a_zxcU)TjT5aAp?p zge7AtK9O%bgC`J<<68$hDE5C^%Aj~o?T)Iv(+0 z)KWQB8#5ybl}&5D&h{mVIKkzn1)<7@5%+Fr-CMAk%XzKA+_7|uq)%I?HM|P6B$xQ5 z7;(5e7&Rm}fk}(}bhoaLUk?^I}Wh`K9tcV=H9z?`f|YZ;x<88%ub>VKTV;!f{;ZAGz!62PZik ztUjZP3Np`1cB;-vgjlvRQ6q>;W_{;&?MDNC!R&jdc}`ArYpA||E2CZsX!}+LPh%S6 z$2N;v?p!hv#4M1`1b1^I0-(Qn*I^q`ulOxVj+f;>)AbC4VKwHZ>cq#n!LR%vqaoI2 zAsHn}0xIcFA3V+ix_^}Fcz$N?EtQ6QTD9KCMjaKDJQqW#&`V}lVx)#Os%?`gNnms*fz$I}R z(+4Tq5glM@54MfXv8Fp$x@@$pG{zM^(^um{oK!|S^H}Eb$$yU?b)i#lBf_png{r^& zd^$R;d?&K?d-wDHU(@h9t=nqj6}kHWnqF4O)GHUqFPC2sPj`%%yCsI5vD1|_cTKDE{^wQtN)JqW75>{|)3sbUPCs$C}| z=6g()!o%ev?*LH;rR{SdISs)Q)U5!yK}?!9_RWrWp8T9=M{g9W&HUoyl4DKp77yM6 zV_n}8wbB0pBADRO_91|siqD=^>^oMf+7#;A&UzFJWwkrI_!CQw>0pH4Q9b~_TqoyX zl*HrnKc$Fb|H=uzLZ3UREzM5ca(mJfD4Oa&)6lwRxEq6AO#pNU_gA?@1eA3@*8MJ5 z9y(zd=AL?&)aL&52di_~ST01Cog^Chf0Z9nzel#ey0q;Y_NMlAr1YsapiO=4ddZMv zpeBR+dXsfJRdwB+$(p+#)u5sKD88R{5HfK`*r2{rL?SkfykAe^~mUF*5e(Od3 zdnOi=>YU~CclPAv#RX@v$Vr^V2f1{S<&1aJxQM%brzK+Ll3YHeouTL7K z?8bf$!x*kd)j8e?SK=0*46{FG360mT9K;!WPN>f*^}iNY9yr|chqu&^y0nU!eEhp) z2{x$y_+x}62zNf9#|Ou9!VujFah8M%^dCxiXhkGCcLX&GwsBcGmstY`Caur^sC}us zS^_2-SmVw|C)}w_H+K~+{aMG@b4OWfQXYw2{#1orUq0!O1CZ%9qS+MCdZ~TjOW_0G zI|>`49EH^-caAP0;!F~)4t3T zZLNLy#LavQGW$FX|8_nl-PO*}3}%rFr(=6EXonPksviF0e87YmnjlXWDb|E=u+2Po zs*n^uejXolC3RSKZnQmYJkNhPoJ>^Iw-Pv#Oo_HJL0SioKfxFJ_nRE6U6Nq`LrB&J zeCbVij-AGLd6W=J6%7X2`cSY8I)7jX12ChT;lIKeAR*9I%&ff%JRd^!(+=_Tp%u9|$G1OsIjw14Q zN~{U-w#;+c9)5wTilE?Gj^zt8LftaOhrpun@NlN0-gkCzz|epD0!Tz&Q#0?2?{gbx zoHg~kDl$%Q!$*QV0*Fq{&DT1)rM1Ag{lq-N_IQPP$ni(dpH~R${|YuKAa`B#r4(}n0+=er$fOr=gDEglev(~=yn6S$8|9?_&ONJ! z1ujzt*usR*a5NskiXbtsckJuWU6-n3E9G%CVTPnTt$WLLD^u^S*Kq6P#`=TCutBy6 zs<;7YnSH5Tce^Gl2wOkD7pfB+2@xq*3VC~`U%Kp~ZT%GoaBn9!uagOV@?*%nDiU!P z?)^Ui(7xt(GsnRwc){XKRk*@EO~SKCdCe=$d3})8@%s1PIwm5JRd79*xIr^ppB6F4 zus`?mdxx$TG<)x(UU5|usroVd$W=X?GC*9c|B7O-6ib9LD)fY^f-K!N3Q@|w_~*+@ zpP}GNO5}~wmM0lJ94V2+z$pE252sj8I~Q7RZ!i$v>&2nk3-@{0Zh^zXt6u;M|B*tDs{ac~IiUv450L7! zS%FqveF2eE#1hm8=Ci0V-x=M{4D^$pdI9u3A0Er4fzCaB+!G3fofHKN*Zv-v9AGX# zSk-4NiJrK^I5q`zilLm2&$CG|aEu@2R2gLSFKqMeUj>s}GJSnB^U4(y*NJ>_pDzr6 zj)*kSwn>u(0q}vQNWLrRMk0 zANO4n*5XbTMw>f+zGGHzjt`dvvi+L)kn`qcz#r=77|bE>nwG9$^pl|1Cjn>GsPGvjkT)8Q#{NV|YA@d!!Xlmsjez5|m0uqT=*gg9cClh+CsEpBxT5}{tMwbMMGC-{za$gL zT&kJ&_@o?=(p7vJ$dE1|eLfw=$uZXgng={+-*!0HZKxV-?r~3X<(=;Yc084BgxSZk z8VPAAxwc#$ho9mL1;4+@NXS4rE+lr>r+?8S`A9!}-r+76U-c_vCDae1a*Dhp_{=nm z*v-y7JM}_JhRF>$=E{>=UQ*TsqLS9Jbz|2nlcN;5&3g)+Ur-AoLMx*bT_AwaGV@Uh z9IJyU2)l-WH{(&UzHE^Jn(fY-FZw7k{0F_rm7O064eXQSf8S5(4@h8_GrbnSJtEs` zOClGz$omyujEgfZCou_*rpM~h^|wvx81LL>%lA;07m*!iixU=y7Si;UI__X{uLIE1P=5e)iw$)BN1Oj^e5ozfy$km*bTe|tk&8= zvR|QksDW}8uVh!=NjElkk?1Y&1 z%Te9Q@|{nQ+zr)w?G-*F@w%(+*F18?&P3JyOl-JUM^`cAwK|ZT{y>}K73D6KE$aVm z02x6U?|bMns&C7bBctDM%xUH_pOLK8o4G@D3noqE9~Ff_prK))TJS?@E!+H_VExJ}`tlD-l{iA4JV^fqOH24> z>foGz%Az=|a}SFeEZ2H+UMIBjq4E|Aiy2W8J+ok;wNjDcFcx@vKK^07#Ht?Y>5>Ce zU_~WGk2G4`@sfWTpl5@)E%PyCfNFL>FCf%d|36GdH}0r-N!bV_9t{h%{ri<{(1$da zq^Vf8iHdFW+#pgE-UP|)4`zfTl}Bw&3aOdP0)Aiop2V&?-Ro!hUNFOY zrG>Tk%0A+=c%DTTUtlFPy^)|%bTO>A?2qfq?ib=@yQnXg^nt5Fzg%+hs(K%jC7IzAd*RMkt~NF zmX<<45xab z$s&4VQ9T*<_8CWh2NU~d*vpq)C)Pg)6>lP1+iQw;iu0UKvZ;s8BVm&T5T4*qQ881K z0XHEhwN!5$s5onNnw8`dwF*3}S}JE`p+9LPCTIcpzej;#PMUNX?(rf&6Dz=$8WrX{ zAML4^Np{ha|AkJ^d#5{Tt~m97_P#P8s_oqykPrk>BqSZ_9%h(f7*e{sL6Gk5P-&2q z5J>?Mlva>b6p?O}kVZm4O6ibz_rURpaqj<~`@Z+v`+?1_wbm2Ar`Fng4|*xK7i{Q? z6}||aVE(->C9HcGE{X>@mlFjhtKu3%Ux{(F_mb~c%r`8<;v;VqvV9!Y#JxW@mXO}jn(s~Km(FO$-y)}7LXOsz5VcviNj(u_ZNXm z$uW)9soA^hk~!)Fp>WgTj`IZYbN6=b?Ks}pWt&nteNHJg zOZ{9oo6cE)2HD#@%uB zX4(>t8AU>s5t?$Vj5#K9`x;FW&Fmq|DDfC>!Zh@G0_|u~Y-gEnct~k5QqbBgb^GC+ zH-hJFLJDEFBr6WEeB(2Djn~%gn$BO|>!)MXV(+YSZM??R3$Y{0`|K?@}nvvYzhQ}U4dTY_wq-8Z<5 zu3ZK`b?7{Lzd6YfC&!_!PC#b+D7kqK0wT`#Y#8Ku=-8P(3t|l^u%Ug@T zzTmEYlp3QJ@=6A5>{}XDy#M&~n#rN6C%9pB_TKAKrJO89?QxLl*`}4uJq;^MFx1y;Fx{nrMA{aij*J}f8+Y?{6+KcJsWsUsRAXrs!#Er~Gn zC}J!Ozel~&dHFn*;r49VL+4_>0B-Hiw0<&IrKtt2Eg!eJ38W-gm>VxWhjJ`QRt%U^8DPKBWX_(^I%t~ zKjKj*+u#6wqBBP7^T@lpbC2(lHLb8NH#U75hTQdTjt!Ci$UKv>@vN^fWFR}=1*GbT z1Aj!^;1ZiQAZ--9TZzH9r&ez);5XQ|@}?k|gMve? z6lUOx<3vA~DVYDLB^i0^P5R~o_PNW=Dk(uNvdr6a122rkM3{%>BMNskdFg2GEk&j3 zA-D1^obDF8sD@nihuia!*qy^%7Dyj8zxUvc$967$YFf0QR}K*Y@YOrDwpJ$&w+K+* zH6rgdme+=ONFe3J?hOpDdI?hHGvRQQb38SIXxPYO1u{Rm>Xp9W`n}V$Ck$FwtAK;b@C5n7>nd|W` zSjZ)7@gx)EMpXz3lI&jeyuOX)g zo{QJV08@(z=H&d+c-S(9In*$QH}C1&W+1@)dU1Ccf4Y#v+lT9iHv`ZbCFp1HqrGNJ zqYy3{G&3FbB~y>qqtw><)-!YwcfV-1B|F7gu3;IPsR5q>O(ypPeOy;pp2ShU#oAWF zi)J_tytS}!cJK0In>vs=6$!k=wm!|Vzq6T+6kU?QPPav54)|?jjgSxxGsfuB0p)zO zxqgusk<3ti+QdN%XAm1DbDeQSKI5n)}nTX=v-2&;3|sT$c~#1tn_$g z-pyi0-sCb~o^#1tMInOyjlC%oU7&`pc^5W!TAVeud26@)dU#mc(&d>CrY1dGxhe|Q zy6bX6Ucfu$@1;e$6mJoV>AcIh=biq#-?U!XB)~vJs@zw`|mP8IqQY7LPvLV-J*5j4dF-j=ii}^Jp#OoTb zC(oMN*Z8Q5s#L8tf9i&7N-;gplHUDT#-%*ilhHzDS;mqBN~zQ~tYJCE z!|$8!xm@s>CeJ$;(iZK~OjnA~Pj+{Z^xhiIl4tDE{siD^SRfDCdD&XsVd z)iy)+ts~vg-~cqP9yCXll5F;^W+uGx63^I3sUVg-_@b7Jp?Q_H#3t>Sf_o}v#dNc^ zjlz0>=W?TI*{n3>Y?C)lpVuS*wx`!;Yd)(wh)EYI$k2CaAJG6`{wOR_a99VirtPeNBN2H#jR{_mzv%z4F9sAygJm;c@irO2AW0X^cF9T_Q!) z#2ZAx$yp4>M`-RTX0&2&w)3$+?pn_Qk@5;Mg0y8WvlCp9t@^}8S>7crk2+sH3G(gD z1vVBlrsyEIW?65g5aYA-uAO3!oTmz-Bx9ngSY7s1>62eHKl!9%?rg$D=R_4=ZeMTx z#pr#RIz?DdN-3W#d`z4P;;E6MU84`Hg?(gV$wjUllrd*aKVH#otx1FCsr9JPN0n_%50n&} z(+L6(-Z_PG_wb#gZ;m_f$VZX6R=kw>%H%qF0mRce*BILkSED!ad!vBwgebzw%R@5RqvbMQeNiqbR+Ri=9n^k* zSB8#iHsy+osZ(@vaSj0i%_qM$(MBrL{~Cq!y#Bg({J_JBxbx`s&I;;Yzy~J7Z4~b8 zbg}l+rfl2F&e*qR8d8M^S3>h zn$;2>Uy8J2s#D9tEvu1{Xr3Ys8S1+XQdgLBMwOVpuq*^+r?J^y~aPO}S&CCRX>mS(!H6Cyb->Fo1P^FcD{Mc-k0&6eeEe+>e)_a>w!{Kbp>CG?XgF*~!3@+6P&SyPOZ-NuFt4aeu zCnIrteosZh>vB{V?uwqMd+t`A7?s->36fb?=)7L*g#wG&%{=PCYtqI9#OkW_Ch?JT zDY>|VUW*bWSvz+YLS|-M#}y~<-674%!M#)FmZHyGZ%-O#$t%M30gaHSEVo)hwU>e8R353%u#jvu#=mW6Qhfn5p9u!O(WIRr zkiMa!$WI{{%7R?*f^(Sbx-L02#VXOoIzemY4kgBLwho^XrCiAldO8>z5B~9n zk-#4YiyaLS;F;N*y0|)<8QG!s9E`2;U{DYj2(=?1fCpChax?>hB^~Tt@xW?s#;(VQ zsFM&pu&9xX8R`lMtgRuY41C2`O;S~X3&F*OciceS%*Djn%F)%q8N|yCbg2rQwsLlH z6|*#Q2Jyi0!16|?4z#RHT`gTedb}`hPKZ7pSi;`K!PLs$0)*f>ZYw18H+`ti{vCbt z8Y-eXvTR}s3NnyCPzU>!IwS1V_R-c|kl-I41&+2adYR1BC)DU_3m>S5aqpp}d@s1fhEPcLd35O6e$~2vU&w14Sp+b;>d!T&GR*C-B3#Q1FBypn%YMxDbHS zxOq@ufN%jiMSu`ofP8-<7S;K`BUW2dR8(CICA~ixD&jZs0TTP$jUc&y*y(A!pzPuV z?I)JN&5gp_Z?^Q0_VeAYPT3LO$^J>ND1n@a1wi_-eI45p7cVdh0`E0LUSy7(FKXCk3Gd`tKAZBBPbov>Brt*9G^(_SQ5XTIq?VImGt}N<1>G`yMMU)U2Q*x`Qc=KYWc$uhp9ebGasd)O(e=spbLU_hThSVe8|PVN64{!W|u36#F;<+%N^NuQkOMH&51*hfM2-(g=z zMOIB5l}1Qt{|WoZU$M{2d&)bZ4!&a_g5u?8zm97B@2HX0l~7Vp0Fo|sbrha{3pPj; za(+s>U_7Vjfk1%J^PM0#pcf<%4*v&Ry#GliQr8~y}L;$V=$e95@1!R(d%K<#s@jVE@Hv-P)xQCN{1d#IqnKqDT0@>-wD5yK} zPVPqn9uOGir0wyR=Q#J|2J#fZT|pqAlf9F($35cxxCR5VRV3(Si@Nt@@8tTAv&YAO zwK_Qq1>!Q06GITFF^(xiwf@lq3IoR2m*}J;1;DJRz zNYuT6k5D#p2F`&1LQf8z&D=pi7IJ)`Xy)k(LY`D`KQd$Z=_>3W2}Aru*iXsyZ-mKP zxqPSUuY&APR3T4O1^u-)gr822#er%P#R5>D>ga+1fN^o7${Zjd!a??Kwzj9E0sM5T z3N$?Sw8;$^JskPFQg}{7?H6iKZ~z4gb0qg4B=jE<1P97spk(}=+Fu~_JNDqH zJn0X_{(_+28v@lUCl^ph|B70kUl8I2@?Qxgo!|`~^aPuufhGCl}Z65<>g}q2F7gszEOJAE^Cj z2%$1cI0En`sEHEjAILq8p&v77KPJRZay3OGJ78{2RYXx%UF&%641$0HNus2!k%bEg zc5;uXsDmd+j{|~$fjGD!ydVfSU@u4*5{UXDE+#0S4frHHu$Ymfw3(HK#J0MJ1nVXvdfyKlOnAn5xfWS^}4z6aV z#XI1p=%TZ02cV3rtZ04*aCqNgJ>u zDsG+hcD#FX8U_P_O@J_G1Oi)nIa-?8gTRhv&Q=blAh3(=@c`at&OjJ-um|Mt>fr!v zES=4OeRBslXVj4Hz`hIclT~0BGj~+$6VZb0txye29Bduz@qkNqR>!*_z_kNJnYo~X zF;H-UfVc`41%bstK%53k0JEofU?~t-8U&UBfn`zinP7PkSOEl91c8-6U}Ze83V;F- z7zm>3Ag~4qtO){Z0ig#3)&YTa@xaE;MkY39Ko|#P287}7$0w{J5g;(YrZGSk2n_It zVge6r0Wb~%TY%Zorvt-( zQo62$sJN)ivC{vUQ3&8P07ij%Z8+edk=%$=jQ&6OT`13mVifRQ#}TU|X;q*#0lDqr5nv_P@aHd0PEIh4%~4c~1xF|0D}(6DHr>bdj&*#?Banf5KWH7dlH)did27vB|zrpR>xuEID!BQu>33V0GhA{ z+x(>sRQUK?C4Wb*lNfgF&A(&T>F;pzcZ@`N|Gy7TZaxm5C%Y*9{vD4{nns1Qzx3@6 z_5gdLT-?ukKdJP7)N{P2Q>_1_cTrUx9T~+F8~8_O4+ZLvzia?lE<-~9S8YHH(6{ul zrct(_eyr8+_JE4#KNRzeZT#>OClLV%`@aa#<7dI0RLrLYcRIuTPlEe>q4W<11LZ;q z4izPNfbj6Y93@45<_^Wo>A1&xIt%_!-2J-D`Ul>)p&$+@Fe?S&f*r3@oc4>Ti1j1r z@dB$k{~Yu z>(&3H+FuqC|G*#QJ9|Kx_kY3ODaG;vy8H(Qt-$s_GxuvpN_@ zP*X_%_sZk>XXX84Ffwy;GqOESU;i9DY~5UbOJpHjzh<($|0N7G4gAw3*;sL{ha>SwVyvp0;tiU$D)7%^9cyVsp+`z;HFE{TgX9hue;2&-rb@(^4P}GAp|8_d!B%wda!%*q1<*D@6@w+=e z&VW$0JrKNsjOQnTKz_|}k^d&g{e3;;4*~&ZrTc36Xs~Z^u!4wd%2w?Ij z$8tJ|oBuj2zC6CXD9~8{z&VUSa zqbs@ZL_|eAP&=E+@g%3Mv6}ds5KUXMYQ`Do+XUc@>Z7|iJ>i_I|m;!m@nfwVdS{R@w>#;B?L{S-lHk6;b0L)3WASh=Ew*NP4O zNE>j^9unfso6gN295o&gieALqF9@U`oPFw?cEmYU-8$suUkF>u^v$Wj<~vN7&v+p; zKk+3Cue8*~V{cnv{wa;`jXpdK_l?60wxig(@1XV}ns2=;M2T-;}Z?%ud}kGP>d zF)AX1>`hZW1KP)_$xk?E*YIxd)z0g_c=;mWO^+|;(aUzPH$ zJ~J(H8E5(uMExS8ur!UVRleq16S<~Fuz_^BgVcTo}NF>v2%^Dd<1>O-ZtOD zRC|l*R(5&6a8P%pcyL%P9_#r05W0dX+c>10yjkkn#;kO@abmq2{cM+@^-*xoeOR>R z1wSrWuq&JHz^Gs}5dxqZG|DYyn=R^qXIv zoO8fQ?~F#>(w7#U9BG~;<+=&r1nIziW?uji{9gm^`&zq z&iGH4Q&c>(@jmA@7V0Uq(O5~SmuB91$f2^i@bq0?JY&m>;+016I1{RLEY{F1wEa-J zyu2q*<=~VF6Cd6~>-J2Q7!CXG?d2wQoD-K$d2cV3H+9x*EqquYvgdNIsG9IfOWK6j zw|T?^@x|n{P3M>Zq^#iEcZUhsvP=P*(hF##H56fqg~GCZz2lMvzph4@}X{mX+_L)q`Iy}L39znZgdjE}K#Khn5% z08c>ve3tJsU5?L~)L9{2Gl!FCh%SbEsdd)Y(gpfVLs)m=XPP6GuSRpTN+B}}z6P{t zLWMyOQzy>IEHqM@dVL!_uf0Q_;CkTaWzg@RF;!}xy2{i)ki^tZ6vb*(SPqN9Y>zl1%9En5EZeqj8X>6B4$W+S>0Ey<4Ie$ zhaREcePbKhsV``9w{De?e$ybzbCb#RN0*~9FvGrNIYOYhj*~tam){Ud%TJovy2CM) z{ff2@6k{)ua9zZ=GS2=HNkP*{G^^v;sj~34tE4f6>xqc6lJ%ZuC2%ASZ+KzE4~?saYb@I9+{E;_m2|!1I1dOV$+^u7>yOKvw0(D)U6nCDfQKp_+&yXHsp2?`yMZ0m#DOl z;`u`2SCgBryZ*iJp`nAHl0!^xR(@cA=h@BLGJM;|EPh=o<*R<6X_2wQyw+Td9QSGq$es zRD21r_gMIJpl+fRG}6=P6_=wJnrOVNaiOcOg~t5lv6D}reDo_+kuF{@qj2q*wVD0l^uf4eY$~d zW>ZIp6&8l;TWs~TERj*aAs93eFG%a3m?T=rsi@6+e%i-YB$1qY+)HlxSuE!+iNV)0 z(ys#_EQ@j;-JNi!j$-C^Vs3d)5GX{(!$5(nrcIknBtn9z)Wwm(ukTO|<#|Onv8ILV z+YfPo+WQw*|Np3wDG4sTmA zyxQ|Dl$LjMB*J1p#=M@t#C}2y^4KZRDh9XQolNz9^yu4hM@WN>`%PgJFHrMsf@JjG z8my7?Z~c>cR4(sjb=Z!psCju1MabIrZokwsRD13}QWNt`Vi!xFF<$D1LGVlS1luQX zU)qnyvKyp?aoi)aAu*86@qB-grp5BwBgHwjFJjFlTG=n3U2U{(A(;45tbcQ)A@%X6 zN76Ojc$C1Rp!2EzVXTL(-mCRs*A)BkE+y=wesc1_;V|`BXceC4xA|p zXXjPPRCjeF*gl0+=ai|?iM(=RGpB1IW!vg}!p`x66;CfHAX*b2Bk0pBDSOX@S8(Ed>Ws+PQlo3kI4c3S65(5PSc zFkJ5xYb*^Xw;Mte`EnR+U2*AkPe9hTxP}>Iylh;a|<^9Kx_}3unM^~ zIe$s6G1E!bn5c5VAe%TjvGFTUbtbVajm9Vkw0CF@>_E=Dy$($iS{S%lyH$Da*$dmj zkqJ3pvwKQj*W2B3k_Z$ZbPm@iD$ho}?Y*z#`}z~h<7tH}SCwj6hZ&!NX&5G(Jq~mp ze5@3^X~8ET`ao~U)XyL_^$h1=uu(M8s@sGbKBS*N`_tVV@hPXHM`73ocxrk<@>LI9 zG7evl4z>zSN2a+=J7PVFQhD4s$`sNs*7SHs(cK$%N7-Tf!C37B3KF%gqS=%$;z75e z*0->By0|s>oWhrQOK-mSO+>id*t&C(wybfq9ZVvOxUrQCChT_>rt?$l>(RVoS@nvD zIqE^W=F)!h<4X)X2!*&?;YO+UhWrxNzH!dnJL1*l4%`>Zf?I=fH!gbQQwm*@9jUk( zjz0HBP58z}R~{#uWc&(Vd!)GAqKMMVD*tn9jxHQWOY~KvuhspcE-i{*IViNyF>&J+ zFvv;2t4104ZLfS(=#cE720K+y0YbVXrYk=xu@d^+Z!sR9(|kIzs1UjCNyw9Bna$6A zdCp|tu*A`By0x6IRGLiwVUpCOeYwXu@z((_Vm{gOf9!%t^ToOjsB-I?Kx`fw+q^NY zTkI;q42gHO_iQvwPLwoVHBB^?2)ls|6;dSt8ljB^^vEXrjzv(P69azqvA;lL;DwPTWP%#N3Y%^ z{qD!-X7bUf^ACHjrqZEV7WC6WNM?1HzO5Ixg5zt%U&QGIcr&Z(o0ukVwzJcqb5u(_ ze8n>H;PJcA2!Q~B>Y&*1kT)?(BG_lk1top+&t;D^SQZ}k~OXg z`p~^}Rh46#W{soCsx5Pfa3k0H!1t(?Fw(R1UV*+2d(oygTtdG^l1c*W_p)QqMt5NrCv-kH%Wc1 zs625mMQEd`lek+%wH5v$hPsj_fc1R(USZzUQ)%t5kii;Vx!1NDr1gh=7xBJP>}IfY zBfMBEoW45Em$hr-%QIJT#j>SPh}mN>&?q7$g`KK|un#mD^qX9E-jiSHfRL`t(om+> z&+B5mWGxU-Agimgb0h3&vHB9G(k#x^pgY?>S56_y`|KKF&fXTET%f=CUEZAL{p7d; znSEAJZyHH1M@OZlcTjQmx$JA&;}c>17};Np-xHaMNlB5|QK#|Bt%%#P*1imU>~lU< z-BYo;AuZ9T+{&ihR^F!KcKE*UIt9z#>@wO5QS7C$cygz*B#Xta>gBl#%gL4JCkd*z>A%Z( zE}2H)q^vgAQ*>7Bu>pE}O0msma&DV}zZ9NY=kVi?eIkZK+|romrQ*8v0$m5kIy7mu zVzAP4Ll+q83~!vnW>B8!G80e=825d-3ybreL8K_`?B=Jstq|_)kHIKuX-W1TScdE> zTS;KDb7&sadVDuWId@SNEmu z5CYT67(~sX;Bq4`t#?ZL{r%RYV{^Spv3jinA3hrFV!L2q+x6x9crx7^r}8rxgsvS#(<8(7>mGq`&jR7<{5Cv>(cSV2X-($vp>S(HG9eo-vA?S7|KVMy5Pr23`s zy>ykZ&+GytdL;INQ`Ng8@(!+%p&?hpXxIJD8DtW`)4A0q4J`H++c zyI(CP>&rynz}3$2y4#w1EWK?$I9YeJvG6zNSVgYt>8Z?&b$`>rcMy!UqV;+(TOS<= zHh;At8ScXp`moynrAOA2%UYueZjth2uN(1SzT z=3B@>Glo%-jnE{~T16Q$iiyn0RWd?2SZQ=G*S7)PF0WlNv1vy;7s-D|Tjq0DD}BG= zlV=^3OezYFS_y+hITppBf=JL}+L%1rKqrfu`EeCom{8LL--pQD~M zQ^cX!=gqp@av2S)>73k`l$uf7UAu?PjQzew?Z-tFlq#X& zEpp}okK8uS_3mKpCB0@UsoZx^CT@Btk^bCq6_e6NF;@ssM zT2DBG#<_27XH^(!Z;VXD7?j~BPK%5^^TiulZLZ8Nm_W3t_3t&Ok;rIWZ4@@RI%G4zD`+X`;6_QqTWplVbFw~qG@Gfuv z_z4@N!llauJ@1|%`t|bVGV!_%#-_YG!YwuBl6_)A4s-kLLyNd&%SJJttw-t-RYqfM z?l(5R)pz1EP`YrxqP_I&c@fTKYAu1tdBub~pxh0TdgUy^x1L0E2@%b6lOf%;A@|WN z_hbs3&{yB}c4`o^yp4}&WQ5$wnQrE>YITU>^oUYCiIDADRrV5JS8Jmx|vmMECI=^;SfNlJN|it>V~h zcT^lnkzB0dc%IgdMp_;yy?7C4$&z?Pz6AFR%bK%*BA#sIyZ#^p%5Ev{jM0Zei^EsZ z;~R-mX!3Xx#780(yUKF6)~koH^q~PaFIv6ws9({oU6d*_3mWNBftAh7Rr0=Wj2(y%9R7(EIJPE*`9Fw9o&@N3irFGmC?P2zwWnQXwHFriZpuAQKp2)Pj75-S z;=voclS&X;cgCery2e7YyJbp~BhSATGASN7cVi^p8h_S?xwv3pg?Q(N7g0IO`01%2 z=0oL&CAO02pKOxxOsCK$D$OHnVm{lIIT7C_sE_oqH=9p!aen7j^z4Gf>Z*+yoyM~d z<26IBb*wsLiScdUT(E)*v(Z{Z%Pj_wMLuNe?Ip?QW2x5f7D~BXk(8fpP3C9DR5hjV zx#ioT9W3201wR{R)op+PVO^Y)yS~7D(@K782u+}H+MIeghKTYNOzS4!=d-gE+&!7% zkF;w`c7LT3K8igV{f&S8utc| zZbi7I$aA)$?cXw7?2s!C3UJpn8V%{o8@cvUJt~fMF>P)zW2|IKj;TVw$A_j5+=4B< zP@5hyVrR~iDn3R$*<3<_cjQ#puV#CZqruA}R3;B%aXaze!w*R74n3By#tvUEK62hY z(>2Fir_;su{5kpqmO=yLJyNVZx$G});v~#x?FHRURBo|IM)I zmK1G)$ELbeBmF}19XzhNW9GFGLUubb@+*Db^+1FQpQRXUeEDK(8!@6n zO77X<^@JB)%O?C8jpuvCESvK1%AHiMzHAa0Uog+y4BMtZ{4g~&6IC;Bs+;XzkN37P zhp*UT)AltoUsU1cJeoh}H#BQ!6Xj$XX=QYG1{G?uUFEr^a|qh_7qzJu(k52Bm&H16RW`lX_2#f?^xBrcc8TkHo}a$xgq*|~n+u8=oHbJ` z=0x=$nuk4i7@h9WXJ0MdlD=)DfiqFMJro^@WOuP4_1HDtZxL2}Qtyb_;*)=KuXp&- zd8H2WUiOZWAT8{g#QF#+N!k?_%eBW;>F@(*iZy@ zm!yYDSlio)nbI8i3NvhJZOz3|pE`iMlkm0-<@Up%bt88ewH1u=zD<+%(_pv*ANneq zW7sZD#vwbbQZI4Eb}JEHuF?TND-Wv+Q#WPJ?At)Zr`Lu)Z|_x~^R9BdD&QzlJouc_ z=~4&78N<7my!*S8oqg7{_Ha0+cPv@ro-KtWycV8X7p<ZFLQ=iwNN#iUbLqb}n7Z`2{(Aa+Oj#=PKyT^CVm=awEVG*|0x_!<2hY@c z#q-FvDAr1wlCoVnKdB66QNDGejA%F3tfZQ9@ReT@AobMX44%|V%`y#@46kN*%>WTneRBsFV z$_S2^Qy|^aYs#X3*wExN@mZj7bqm9tk371rzf9=Sc3Y8|9z6e$bRxOr<2Tdz45w_k zdx5fmLEQc7jV6Z+?{Lt(biH-n6iYM6j0pwPBXjZxr0&_=(Yn)d>uS;6o8&pqWfO8k zfnN#JD@$`=ip(W`Q99nju(Dm~-AFkc>WJXUuS=)0(~D}>TBPRt8b_ZJ%XQ;6lL%bt z!w%VA`pj3}v;_hlf9r_~^P=jJMUsL@=R22y?kV#Dk-Lmkodwdm+tJ^2+ z;cC0i?k3acuSOHQ&za7ZIpH40)Mrm4p|#d^E5t0_hF~E4-i!uUeXn=zZtSD}o{0i` z&Dm~O4C!IM1HDD^N^xN%(LHf|{oUSAB;_gBohwsp3-oN(O~j8fcKqA~&0jIIm=jT4 zw1aw-daYhm_zEMDtH2=xHzxTNbIN(uD>0pKC)$5^H#2>GGS4yPv(N~X(K~vRBekKh zyYe#?-c)iZZkEhhI~$B3W|@gTO&d}Nq*KfKJ)Cd#`UXIbLc!UZF{FZX^ZK&F2uJ1)6z}Cy71M6))%|=X?1P?~b4zZH~r;+OsCejZcA# zAbZ%O*DE4N;}2Q&S)IkI5Xs+GiIvt%R*a}Ldek^7yG8hnOj|$T613=!FhY0&Q}Lbz zx@hFc9ZX3Pr~CA;vR{$8SWRbflUOIriN)7;WnFhDAStvyC}JkgHq}^?8lf|;E5V~r z>&9Vlw`D`{3-#x+mkN|6F%sJI-JvGlNJbfZ_>M`}XZ4QGsA~!~#x!*g-nZPN@Ng&~ z(P_|Wwd^nca;0g3a_$3J|J*rRHafHfV`3UHf>QhEfxb1?eJ_ThD!v3^5Zsm)|B_)s zV<`{vA1K;PXPcReWxhs#r{pDKQAISsMuW6Ql67)EchBG}HhuYwVB05C$cJ=#6W*d^hazlpm;5v9$Vm0~R7pwt(w1f@D5e$N%lBW$N12=Ct zY;xvaC}zZ_&F0=9(_%=%=Zd5VGmqHg=SsvS^;X_$=b9xHBc2zKU#P!Tf8zp3w@)hG zNod-n;fBBPM0H~G+eq`oN%DgLk`ND>607UaWVD!AzoJpg$v>cSn3$pUPN#qtzL(?B z7-znV-k@eYRh1>B4=ue!iPy<(M$e#270WYk$~dMw-YR?9x^)$UZVN-<&^ud>eR9Vb zGtITICitQ{Mp{*32iQf8S}c(L^{``vnjQMYK955$+iRh=51foj(H7o0k9zf5t4nuo zb(0+iWKG33rLxU)$c0TDnuQ`GoVr71KFG_W9VT91FXOC~@}gLuMUT%5A764OZW2n^ zfE^^Pq)onX+1e=@W)|>uT1C@jvuaRfo+2U2xq@{k@1BXMbiRYuN3sK)FT#l-Dhuz? zod_X)SFo?Vj<%VeeBB*I6{}|B>C^khXTq@C2}{Yo&CAgNAzz>Hycn8{y?EjNbop3P zh_7ky%Y)DF%0e0M4~9ss+T+X7@-C%ir4|XX`2;!&TP|AiUr&g>=A;9+e`MaN4zhx0P`F1RvBXq-eCa6EusE~&*dAFz{<3Gz+2~|No-q%OohEy`z&g52g^^_ zocU4{Xn1#$t)H`J2jFkRR^czUp&9zpz6l=oj-Z6DJCm0J3V7&fQrXUTP+6Ow#jh{_ zqS=s{oF%<;_eMBv=R5=6t>o;R+^_Na!ahQGCPC~w5!S*J-Q!AKttm%AjR(t)a&3-+ z!yfrWiIlV--O!Orv^y*hXxqkS*{?NN!My98{2x(Ybd!#dO)Vjn-(t^`vyxCwKU1R+ zGF07NI7QFNC6Mo7c}wjpKJ2zh&Dts9m!v1R9gD= zR-dSa57SMkUedYG7iK;zsOJ`~7gt!=1&hT#4^LA|mGU2M77sm3AQVX_eZQl}I^DTd zN`0uR?%A^o9Ap`UnP*L!Es8b|koJOzKvjbH`7e5km21Q$81LhgN*+blZR=0wmc4Hf zCbtn0oPQ~XnVt)!UeVP*tD15B+FVYFumg!AJ+Vm&c9D8$DYJ#zBYB(E72zn?sfPMn zIqo<4zp9^Q=&Sy87=|5@`!0W`b?pu1#hi?);r{k5J#9wK@ttVIk{cTr(!K4fOlvz7 z&c7LS=5_JCtwmUR!?|@L87;JqRedr!>v__sX$Qtmogi=GNc^R1izyM_ba5Wbasnh{ z>qj^QZfKZ)_%a;uvf+PQvu?jU1_yj%gbR4!^Its&=XS>N@mQ&w z?T8n5iQPy=6vESFq@ptn>BLy^APk;7*ot}S(B-vDcePu=p?AK!+fxI5pUq+YP31Tl zWWXq_<^j77xlXe74%&jMb$FpIJ3AUFqdTUotP`1>8X}WU`fXol9AT!N6}obzE5@@@ z^g~tci_GX#(Td}o*K8;eXi>;zVbHbq@ji@sG*@&>Y06MsqbthBjj6!Yd66`HMt!t%$$u6NE3=xRr9Y0; z@Y6iTvm*}-E)Pr{w4QO49gX4uIFXg0T+^v zKBcm^v|W6&=`i?q?6YuAZNT-Tg)=?-n=zz@Mpm1N%k~aWO&1JtGcS6$Iy!qicSUFB z)75_Ahh`mp{&D8fGkI#it?{E9<40VkWAaCPAiUDUMXL7NtC{9%8&C;T7$(I%D`rj~IHzr%|; z{4@V)&5Ec5nq2y@vi$tkM3R5OsoyVU?ppb{95%*=-q%S7bHM}?$&ns(8Zr;|M(eJ1 zuh5r8q)Un`FF2YghVen>^(U)qfiK(jRigh`L@{**E&p+6Pz&mc?{}Hn*MwIr$T}aR z<*ZI~szVe>H;-kixWNh(-;mVO{(wm?V<{OQpZgMM{+84WXSYMrcQPUS?dgX{&_L}9 zca@E>w^3F?xqYHmde2KP4|aF&OnMM|pDmnx09h!bmMrqeNJSmhHcIJ!IHd9E#$@=c6rw;9T$?(X2!he zgwBVs8SsX~N{+D+=6dEnNFsPdlRC;Ruq}IZFxD0B6rotK_8tT| zNh8+lKSao7Oze)ZTIRUq*P`=%_P7eQdO+OCHrCxRjDZY4Pp1)UEn%Qfq#8t{2gT{Xgs zN;lpi&u+V3z+-#Rd}Pr2)xAJra^e#+I&`10rAh)~{A(Ey0TtKMb2bs=-cm5ALd&#` z(g*BSwtxMR_>Efv_=w%*lBxUz&+r852 zCyblnmC%k`h$J+3R!4Om^ZID*ZIJkla2#19&u+Wm_cGEatIuh!!!hJDWCgkR&zl}W zejYk;4kC50Ero(m3u{rn+s3^Jc)z74dA$n~(NZjJ#;G5F+LwC32WjrwfrP|n$?a-5 zO&Ra>filUrnj=1&E;*Nab9E*@3Lsh|C+U#+4L(pBq%6G4UQ&Z7;(aKJ+19{czI~{D zu5TfVeJ1Dp%5)(n+O}$vB&}tHa7av93b8{;LErEn=gUDB*JbTL21E@0XHt`z)pHv8 zRR7`2R%+L5JU*x{^oekdw%nwb^txGj!0}s^64P|5RG}%L`XLmUPy8&2Sk50L+nt0u%oYdMo z=E~EKV;`w$##!g2s(V;TIWeI4kF2nCy7F!u2c^{-EyaR5RuS|n_rZr3_E3j!Lm`FJ zILaJEpsb~1^-4T{w)x`;{g(Yc)z{y)jQ#wH2Uh8?AD**Iuh(PZXrt7N?Wk9yZL5(p z;e-FOrQcDAK&aozZy?Pf5}l@{)#(LoaB>uT`BgHQ-1~vYKhEm@4y@ zN$n-OPAb7<$9H*1wY+@sy7_W3I9TLb{A|e2!M<*o^Lr>$b%wvpWOwLU|IMf=BVA09 zuHE=Nbx7U#R?vv8pE~;AJF1=v^he-E%E2|&W!C9>G;nxR#v2wFG?XBOKW$4;fE>`0 zzc$OtXd;PomUn}^DXiXir@pM`7CrXfbhdv0Yy^q&=VtgZ)@$#`g%9XIJ@5|!4rjWT zh5!pl+J$(+rV|3P{#((7iEPU5t_Zm!0;I&-w4(gv4G~uNZY{qsNa9V=M<1YCYu{@L zz`zBqe2UCmu4iwUb<&)%myyE#I6mmBdBY#pO*{l$(uuJ_@qEkBl>P2;r&2?MVjU)m zi=fwx7O8k$R_dxcO)@V_REtA=;EdB;fUjH8r-TjfLoB_BI=s$B$HD3}8mmG+5!35M za#{9&ymYU9x%#sKYl4cw$#zi?J)oeKTxDtU0)CTXi4MzIg>|Xn<*;S*5r%KPdxRx_NdgV82v*M_4<*1Ep=S9>H8af@+TIha*aQj?MZTjbK+mdDJ?EV$_EU{};<5LOI*{ zB6-EBJgZtCF8hF)^N@|CN~@F6z;&e3lnLH3o{^efOiTQlKQZv^svjW#LRU5;nM6@G zK;bGZRmE0h@TF>GwpXx~aQ2X<_=b5~c|H1mf|+hM-5O<>6XfHKkV9B?E z`Av!S#=As(u^K5T{{A_W05JPyS3_pxI^F4}RJ-&IK5B%=SyLhrF+eSpVxmhN+8%eq zlwP~sV}t_LYuRPLkis@|9nSPy9i;9;8K@+!XNCQSq=qJZ5Mzi1a7|zetR&@&|QQ#u%@T{wM`*h;}ZulNx4drEPI)A`LhPAi}Dd1IhIBg*S}lPrltM+m*cGM#RF z29F{+`LuEV>|QP5p$xr~pxn@%1A7;xhgUbeDN2ydoT)dn=^b@!{7 zROBL2VyIcH9t5fd`R@+Kyz1F()WTzdUKS4hzM487!x4R7_IHqC6p35d_K)(q9qg+& zEn`P}JLFUR6=%&{78)UP$UU@k`#%~lYzE3i!sVS_g}1GqfL zan8q;;S=`_1}*DhP!0qOHwe9U#;SeR7;uJIGJp1>rWHSjDvn2Q8j~Q>>zfSv=(yjv zqQdWQy|ff#hW4!D~(4gITWb0(Q2N^D!l>Q*&lBF zt8uwS2qSMxR5U%~^xRH?EW?#DSY(msi?6bg)&0-90RBhKF)J5%e(&d&mB_%A^HFvePcI6w)w2lmqYFe2O-W2)>xGZm*@Uoi?NIE&tW> zKbl$JBK=3h3T*8A45Ax_blaC0Rv=107`n^r3E?q!F-~$B{s}6z>KbZb@`$JPS3(I@ z^Si@J&5X|)YzAT*u;^mC96)fv%ShMAkl;G4T*EDPeF+rtWP#dpZ_v4ETW57Q(2JG>vNAsokCEqi9;10ASxEj z-G#YQv`tq!As7&JZ*QFJC;^q`{`)i65vVJ!Fj+DeuC1 zRwrVPi8A{!CLI^_IS{`CH@F~c16yjBe?0wSd=QdJHUwrH!UzI?wk8B#s*|#Q)d~AO z|2-1&fTi$8=aa(kuj5|2#Zn9e{fgsVfP%24&2I_xauvU&P)bFBzM^lbO#AdJxxcHVX{x76~}do3@JW(15xD6PtpzVUDjU?4N=>%sP#=Zk$)UM%C^r4Rt@iFd6eMb#K@O} zX<3koZeT_v?X@Rp5bz_q(J3Zu*N^k0bmYb$z8MaB}C8V2P z%7**FWFCpmf^*ZnDQpEvP1{Ym#Tli{|G@J&e@lq%C0YU|zUuF-Tt zouVUKug}qm_BG{WnC#Xg&yC>Tuz`vZJJ>G27`QK zU>?psFMY@z!I5Ok9+`dBPjV^!`D_E9+vfg<5<*b++ri7ZrbvyWR2j^7f0`bl7X)vY zKLz+Y|s-7jXi_!{GPa#7Yqf;vztz$Y{=XvNZ?eDN^n$~9M7G%CUCjkWPLW)CNL6} zWm+~6rogZB7Ccn;1ZOgDTx^XbETG_G)_ehEI#|AonuPXPmmSK~(_g*g6Kq`Dbvei7 z#l$B{Ke6>q#rcO~22T~F+aIOtr=F(0DaeA;>%mnM&p46R z1d12=*JIGAmXg1$+a?+N4s&^&P43uyAciP3o37$J4Qc&Zr$jpcdM=>#g$R|m5Vh&a zaADzmo(AF~XMvO?k72#+W-H1RhvMvf5O+rTTPcq|J;EeB3TEH=!q)(eL|(>SP!g-b z+#H@20C=;I2hAp%irG{_Te)%6VGj0&nx_}Wv65=K1iIo_*6r?hi;!7S!c&CQNYsFk zVb7Y4fe^7ri1Uua`Vw;NU(zBBTUl+~>eXKz=Zs|&{=J{i5JG7zl3zO%{WwM1-odqF z>4a=!h3lt9q%nd>{K1vy3XkbqU~66)eCQw^Vgd@#V!^6mB`tn{Fbv|>b?*u!UD5{l zJWNL2`%M)lyUU#q!$DU0+NGKA42AvZoGd-Q|EZuh#ayx|zO4{;DB#-c7vK zc877#O!Xas0kvNuo9?4lPo&uwrCZ%WRPZ2t_tiJ~xRZ zNfu_g{&Tey}+ zJSU`Eb}CbUunfkPf0mk>*EDkr4cat-~wY%p!9 z-iF_g>O@n!>8AG?s(j2ogk41^n&cP>yR)UnbuGlvL3A~#HvOR&0gBiygc6hhnt7mw zmJZX9kOIu-QU&%|_7ao4A-;~@V^30*>w~76=*Dh;@-FglkzVD<8fYjI8xfsOGE=W_(t-`QJMxo68(fX-#rH`yP8f4g*%VwE5u1!tpGprF zrjwWP2TKIS_>M>k26z{(0tnyBJWBqHFJr^y0Q4z&jgBltXM>V)nA2!~sopGK->3?_ zg=GbD2TpLkE3>zBJPAX{Po9K6Syxb3a_{WRgM;&n&mxFx?t(b%My_!x0>RpW-#8j4 zAI8Bq#pTS)#Zu88h7lns%>1t{xp!8eBl5Ai<-~RC+WiB<$R`oWuu0RoC zBBn?$94Wfof=>=XRbfDdF|F})^IcJ)#$p*~&smGHNo?Q-q9&%ZK%IR7{J8_#Hj}p9 zN#U3%ep>DQQiDX?mWaq|s)czXSN$HR5dGKab?8SFN|(Fsjv^c2j8s?7a|3H{;{6I7 zhXL$zjcr}ii2Dc&3*24rWl{m`>nmAz_!OiJOze{f2lY-1A3l`g-IpASJ~@p!0UzCwuf`c^B8E8v5c@0_Kl=8{`!ofgqqg}3n40Ym z(#LCkW4GLgGFjW2Gx+stY@KNDxPIDj7-v`5gy-(0K-8WUiml*w9)TQM*XB^gVXQon zhb_g+J>3}RBT&d@+Hi2-!0t~xJ=U4b*?T_``yN~Ck2Da;XDEGAg;!XyBX$-yy0&pr zdnl;xjGasOM1c@pqbp9W z0bg{4D-Qn`Y&s6_k+F3=eykb8_76ulvrIPgXeECRa_`N!R;Bxl-^uSF(mH8GQVsmd z#eV>$cb`c~6nip5aUK){dtQx6pN%!>Xw<<>FD}bVgEjF(zIsYxQA$POd9^|~2$B6R zF%g=w(Q_j7-bxY%m+d6+4Xs5IR)+cchZjsVU!o7j&hIRUJly9x(IWg62(RPdLP-J{ zQos4ckK~mwEP}+B4xc!&Qt4OYx* z`Nk|7RzYcgY29)MU8q7Ay!LuAlKWYuBzJBJ6C6KECXIfA46QXKNccf+f(q)`qo5L- zT~9IJWN%E&Y-16UvR1QhmY#kHcIxR1Js4+-PVN;s{yrrwRk_i1#j2?zwYq~iypU-{ z1M4er<8`K#O~{&u!}0~&UH;c{AuD(Y_GIkpTof727~>)Egg7#;6)<>0!xUUh%#y^= z6^^H%B?nSin0%iXpQ_Hi{ro)S_qoAB@?>n>>iDZJU=%vu*L3=lLa%~99fCoJ2>r9K zr6GGE@<^y-d$XYfL=hP6GE67VT5a^vW6_VZ0+SckG273jnu9&>0-K(OQAZ}eu;?`F z+=foN5(*#CUayP#qE*H?uE`;Ej=@B z4Tq~P&{&OFzo#vndMWj)BEIM%TZ?;N_q|JSTEK3wPlObhk}-9ix1l>JMf7uxofQ;8 zBo_&>dDa`p4F_-Rk&?I;37^Jvi(fkbDUaFhy)LN+S5;>TfM}%b_ZCEjmy%aeiSY_~ zxWxq0>aCJtV5nX}4?CTzenAvNW2`uj>KqsU-N;u~vOwRXECkuH&Qx~w+m1*KY3e3| za0FK%TMADD7AEz|+Ert`bl(l+$GcAPkrt9>ua8*jFp0jRQ{|N-e^451Nohh=D^_R| zth0EmOV-3+Up5ZOw|AC76bM60={7HH?vTTBaSH%E9*e<+2rvYP@n_(L`+>Rsw$%Ly zb4lw$eXe0EghR z2VKX>F}G`l=z>Y7=J&rS_$)+5$1V#oec-*XtW6dPE&_PN*ZZ{X;t>aV7lOA++*B<#w{3_5^v2I8& zRS)A~9jyTRX80!UKjl!%gC%p?5)50W?e_SBdI=B=zsP<`6X0I{tF+;oSajS<`i(U1 z_T+TuvZt`GCY3CFcTHV$0%zw(zohA~31ElQJ`_bpvItKp7do+Luh@BrE9WIQJf5| zoH0eMjr;hFo4+AGXH7_&g^1lAAapfXrfV>jO*?Q0DSTm~!tJ`%{O(3Wd*QgLW4M3X zD-sSJeB`6qBRV1Lpm~W0HcgKFj8!HfX51|gz+y`@NT7JqRg61+q6ywUho1@cO|Nh6 zE^p@rw6sj=Y%#QL46qg^KUvkR2++UB)@baoufdxw4YHl>i)5*NL!~oOetp%d?8N7+ zm?EL3M70ahL`OM)p1Mihh`FA1Sm_04(~;5qzGumRFTkp(Le*zt5O$9{xt{?Qtrty{ zowH4kGZFt#7Iojs1XqLp?w5D9(e>KRs`EbQQlR0{Hk&&dwOGKzh)*D9!`LtqnLz#p zhZTXMlhsI1Z%SKwT{Hys{h7E(+9ewk;KS##O`$&}Z=HcPT%3R>_SN!h-w@{p$IV*opN$UK9V(5F9;e#) zfgFXy43U%%I>XiLlQ-3QgjxKYh!@+WGGCLW)obbUyE>q|C4_c|aAO)4PixNOnb0z>$Y!w8`ni$IK)zpWBG^oBADMOxKW6H{ zDMfB)JqD?(z0oe!W(-oYg?Gz^#`4%OEB{cl8+lDZ( z;OHAK3x$&2<=F0>hX{FCupwx0y*QHm0~!l+nv{aV47N^|2EEPgC(bHZc0fbGi?xtD$ST zQYiE_RFKc1J$mq9Mqo_#i*xcHT~_ghrT7Byf0t}WiFwGXeG2Wnn+E!QsZ_k>rDn&`>SsJA7Q~t`jb}{!)@W z10xb)^VIgv&W8X#>rP15d|3z8A{O=hOxkT<#&aFe_}qcBq6eAHnRhhd-6%bR^>eCI zByF*?ApviY{a<6}WhACg)Be02Zt3C4|CK^}Fc&9SxJ6QjI;zEMo^H=81k!0*ELtxvN{?+Y~+HfYw9(^BV_ zuD)J~4zOIV2EakDXg6&-G)5cek79d7nTZwXc_x~$U7Ou~LN8zr{n!#bj(66>zFr10 z`fy1uMfo`)Q_lO@pu0>!Hm>pa9u@d$DdkSuy{kxRY}y4vTKFP|Zk_YQ1mL-$bLb7o zw%ZB$1{tS~8KDElOzXp3E)3i%AI9(wl#b|+yinh~5@3;~s<2->UzEa}S$4tSJO+Go zn~s9YG$(q?K;q`W1{%G?SH2ejvOpD`*zaZKVpCbvebR?jrNCP9 z@e*I6(4I!5kuY$0<9l|4g9sx3>`|HCGWZ^RLY;y?gfaumn2Y%%oz~eH&-Uvi*N7iw z(15c=_X(sVcBG}Y#EKJ&a)!=(eY}z+pP}J2S1h?#?iye~!9Jx$5xDCJQRtvr+xS_2~!${K@uN~?6+S=679Gs7EN>` zNh9wLHMv;3R$hEKVDWLIT+X&#g@Kh*KYMR8l_-gBZ+!oy{qI%p=S@plO(IcoxlQoN zt{24e2MAG)-i*gzTNg?+;?V||#plu(`cq;DL#J=PT2hUCk=Ec&Bp2_?^zlGq-`s#1 z1*ljb0mx%=J+XhP)LI{vbIf&hPV9F%DA2i?fttkKdBBml?Pp9G+4B>NEJu2Th zaYqKP!(nOBtDtN{)8~_i{+e;sd9}H9BHS5jmaeAmSBnUhfJD<~z&nMpKTwnvbLSIw zsgRT5E9ar|te)e~wib@leKB^rrmT$Vj*qG37~r7NJ+?8Ff4}37C?md_{<&RLzmV`j z#Ih`g2ii3_Y)w}Pg2tvgEQ1Dq&mX>Sxhi{}KrBYo;3846eWv17$M&y3>M!kTb}o45 zvcc+N2Iu-GBhW|Ld=Q_hETsiU=Q;(NH9iXMIFL|QWBlan_~y)>+yGRrDoR_Iej%l zP}@&ljRUFghYZ}Eu39{bU|}kyqzslAbq?3fi{#CWgtsO2c;{{)^ z@9S7SCilVSGRJ*`$}fjaT@=97avyNekA8^zC)E@5`AaaI{mHTA@poliHG=Bo1cME) zW1%yH_GDbr?Qf`pej82D;(Eh@Xz9Y(@e@_46*77fzWGayV-%v`vB%s@MPdaz*Ll;s zVP)^Zo*gV8%(7qoE{de@syixajprXvr3PpC{HBGk3``psnnu8Zs(5xqFuEgryjO~8 zQ=Kn@)l_Ia;yc0w`DwndT)B?*@IB_MAJvnoLlcW?w^@TFcL^wiPSub7)xRBoE(%|D zLZOUU!#IJg%ull#s{^@2McVEt9wN22V4byO6Ebc+7N_8?u6NcG|IbWclZ;xGpldAX zqD**JK_SroHq@LRuvJ#%^)=CR7W9B9bDMTJl33F)x;wqP*)P5CUqtUo>j9z@33l0w zmsjbQrwQ^WenwCJ6^d?W&qPT7D3Ta~Tsci+Vl9Bjk0hCSPzC-)4NiXaZ6uSBNTLl@ zzNO8w;vb3oys&ZO6D55aF`S3m@k7*8{4P0_F}y_|4AJ1#RpB^@9(ouEQY_9z^`-mN z@$CAp=DaN7*HE0-c{u;qhFKJbaFWE`9!G?AIRQPwF3 zMDUZDyYUIM0I0Qg3SL++qbg%+n!`@NFYBL(3YvGMm)K8U<4NgDHktN4{J}eILI?gf z=NUc>=$g5q_Ks*IgISm(dz%R1yMYDP>~rO5c|Eq?fQo1{CmS^$zrI?ku2K_3SX_id z>|Q0JI{U=ZLEw!Dg(L7Exg`>j!bN?dd(8sC!2WwWI_IyZE!@Z~<+po1I0!)~Ot0&I z{)g83&Rgu8*wWldrf2_pMG6Y=X+q5<){9Arny0Rmw9#|GT%s8({; zUH1Q!Os>f4gGE?i55n<*=yb$KLxeo%McQc|5%slA2=XRX&#!q`@d6J%?3tlg1*Uu{ zO2?^o`reLrVCkH$s6@eDk9J^U%uJRF=Fw!-mkG8D`30`|0yk>2-@$mz=H~WJr<|XT zK$PXw-sm5e7a&aE*WrqQldFjZfxSYVOPNKtCEy@ftl?Pch7 z3%gTU&6kDepQGprgl-hT*>0G~ln;88{Pgb+e@TsKw|MWp2kPj-W3tK#STbI@kfG71 zbP-b%$Wcixwg#J;(9xYbC9w}aH_WClOt@kTD2*oZ$T|$ga#UX`qrnewrfFe(ARo!0 z3QD^LL@|zMcFbjwu!K(i=4a=g;u6>DcF4#Y#OqL zsH9>&-Gl952Da5VV!NjUpUXQ5HQG$me992QTf0yS0Ey@+278HxptoJU85jLIlJ!d>5dRu;^ldAWB|2FF?=Cuw7%r(kctM4tO@=1s zsk-W=M!WaytfisZ&2tUj1v%SuS`Mb~tEnk+QG)TYdmSFHK42O74Sc}And;j-<6^A? zy__NJxbDK4S=G>W{V)1p?f_(+1JXYnGQ`FBi`80VDF-Fnp{yYSW=oSJ%>ld9*bJf$ zqGMV^=z%Pgd$wCMZjg}7!reu7qtC3KOc<>m4e;J)Pz6$F6>bN<+?M(BUp5Xwt%vD)#Ws>#~<><|i_C@W|SHj)c(`9ADr z@eL!h7SgO6k}%pIOF1}M9XA|mLn0Bybj-|romKAisi}7E)vzE;H*&j~1^FlKQYDT` zUz&;J22ZOu)=$FI`C(qhqS8pkz6@_ZGO-}38KEQ%)|U%)!Mr#|L6JV=lOZgzw>}^` zAxeIHnTcSd8VeQIj&0ST@`sb11|FW<<8&{blD?d;Ya2c2?_xZi!}|L8Tr*=5$hk@J zSq|<96c1RwYmYQn=(yFspu?HU^R3wDVOcY+0_QN;W(9fziO^S`H~VLIud-LjMZ4jM zc*3?d@7P5J@iXudo<{pq;6UHLC(Y}O;G{lMt^o}I<{ESyrO`Hfz3b{{KaY6a3V@0; zqSh7bi}#gCbFsehA$`WRQlT0zrIozxoJ|vTH2lxSH`Z@U*KF`HmH_SfKBS)|9(yR8 z?iygB&aFVM$LVed?;EP2bd4tB65A_4G*jJUdV!!qqQ`jz9qlPyWTS-aods#)5tbA@ zD%QsT<-?o2{%{WED$0ZDKe;?3<#+THUW$>j%x3?Qdpn1>I;)ZT*$dcmY@T>LC(RJg zqef;-051-~7Ya4lzm{zV>7e@Ta4IWzR4k-Q|lEG-LH9&&%e5>Rh-2P|P#+~u8>V6+_(R|@YaFaC?joe9$(UJEv#|Tbtt3>61lMvBkF5%sS zHO@~b9{gM%v6UOIwt*Yr+ZsfzI-VmPB?=d7%6P3L9~25LMC57sGgwaZni+9A#R+N| zS>v&}qW^#$S~Zq1b!rGj=)7Q4Fi1vkMz+UG5((b_@dR0OV1t5zYIAC+NQp=>lKNV5tupqBnetD6%aO znM*kOU8BO3obBZ=z4=52ng1gWc?X@;;8(z{0j^XLD z&^%oM$b%I`Q-H)&_aIzF3V3ba>R+0nLH%V1o_@giCBAvijMyTx7sPQZ4?x$kPvpi) zc@-6V(S35<&PPTBG1EX0j~z=X6o)r5fhc{x{mgdHn!&=Iise!Ll{FUf>l$uvPO5t! z%mdIV9Ft%wY&CeXQbb*s0@7IrOI`%_jXVo3QzHmk-Xztg?UN>o6YSxbbBGq#k$9{j zH{2SkG6iFz4;p7dlF>GOQe$8y-dV1-9ubGbNg6|_O0)oQ&l1|F)DZ-fRh|Ho52(rh z5O~G`Ai7X!Ylozpz-5<+Wl*Sq#{mqgl(^qJaF0RblQ+zTJ%)LxXqrI1flyfto_0iQ8%s0F3IS0VB)f}Yzr zz)rjuum>nbU39=@`6&;mdfkV*g?fEhX7`tlgd;Gr zH-qH{^cmhhqBSHo2fNyZ~fTZF2db?#xV_ z)vx@GvFPuI$Z?J^MrX-k#w~7#nDCw3p58&MtduS~(><$#di$i7$1V%#ENHcwklGCgr*-o?KE(3j_Z~&2<@zW3H)AshEReRPdRW@Qk|}JyXHN$R7tdpud1yP?p>Ll ztOKDA+oFc=kl4w?qe+(k<$!k>9yPjdk}XmlQi0FfKC*pCO-;)9I!5FuJtz|rv*DoM zIzaaNgSAuPRdhiAFhbec;kb#Ae7Z6GOV0$eI!s8pi(m)4j0%T##EoK7+>V9NbWGq2Csn={K$rpNHfzSeN!0K+2B(iA>j}-)ud*8i|@$7mp=<^4MG?#1)U8 z?QC$3Xj;}e#iy8>>>Z5j!{vkXy89(dA2=k#YY9reddb37 z?uSalXtY#G>FK>7I<)Y$Y2k>5@ubzc)7 zpm$fCmq^$ZBmNvZl3T&q7U@?<1lMaZcV|r4?TC=%^oOGRq@%ex&$+4axO~Gj4d(;AkpK-$nM*$RnriDnu`S^^LjB*69f7cl+|G(D+v1B!E#t+ z3iH6A%Zy48U-maX8%X+=$i8{D9SAd^u8DGhedXTE+WQ^LvaOwz1b3Alf)R0IPovhY zc*MjP)hQ2$2UP`)(f^p=UPz;vdf$6|!2C4gR9OMjR%6RL488~#F8@L6@Ev?TAc+Yg z_H>#L4ej^WWKQgw-Wl_HoIX`pQ)j;nGBYwuzWfb|HsJvlfOblu)aML6B zbp%s-5waIgU|YWOwtOaGH+w*^U`&^3KlsFQBPdC3uMnbm5ZL(9D_j~RcCxMny_Doa z{~jIK(!~STU2rEJppjG%1ONI0(cy_1=7|)rD3l2OAjDhPnDk#s&`c?+aUckHXhOEw);8rwX)4_#L>0o_VEJdiP-CG%l*9+#z_YjciUntm5`-!Xi=e2U^BxGP ziGq}$>z22$%Il`0sG^|1$~`0%0Yl|uTT5>n^un;VIK(h+%v2rUW9|YdCVyFQ`qO?i z_)|wr*Sp6hqxOcfKGQ;nX*soGncM%EIOcTHx5)F=G0U~PkdsCO?n}-el>r)}%k9Ee z7t&ML))CEI1OtLRIgXyZWm_JiAqHUBM+i;?Zd-t(xak-*PgdWu$9wpQ`_GxPu^(xW zpPn|*>BFKRS3I8@R74A?<-wC@z^r(XXSlsp)1|-H%*B@a9rKG2A3iKogvk8v`CnF0 zg3dXFwSkqQVKkp<^0!@xk3ixR)vKZLStl;azz)6*HjH|q zO<%;Rjh-XA&Urv#I_anIiiE5SiL3cmz5?@R{;o{l8br9U&(-nDS)bKmzW@XCzJjqO z%7cCyL-=fjg)9@x1Pm-ruX&=D%h|uCA#gd zLWE-^f_-|5rf;q%27eskFL^TgnW6mTlb;>E%*3?C?BwuK7c4@xv1gmEC!MWSPQ`3q zGrSM(nxwa78rLdbq8U9zVO$!RzJw_KFtOF_)f25;hlR#q<=GR8O6@QfAEWHC{co_V zb^l+bnW4Mx9Yfg2I~IB`=OWj8vF|lh)r4H$4z3P;kn8=s&bm$_QjNTcujB)fy)Q`rQez_=XF z4>@&T;OAYm{hCmzlFfqza0`9*f&|3 zyv#R}MzBntwd||xevD(KGbxqd(5{V3tb|a5#n;R=P|!|OAzz=TwfyQ-1UiCrza~@8 zAy#ARh)IT=S5bb?PB0ZF89WU(%Zd7qe$!iV2yMUhcc7_()lqQ>B4xa3#gc!(7>-Xe zlu>MuOEY9Ty8SjwbE=cUo+P#n3XDn~YL!%N>8{Ii_-`mVIvI!}6%#OP6S#G9aiCc{ zOFlb0F-bYIgtyLrt~mq&$=V^MM{D|ODnLiHz=g{0BDW}L$&SjdTGUpp3_CH6627bx z6UPRcI>y&AR{rEr@xMuo2YX`|E*8I&m?& zZD)Z7=&sNlBZzr}NHqqR|xxRUZcZoRbGu4>I z5#VcfJ|O4O(57Wyg3wnDwL|z^lF5X8Mg98v%k_;&N;H`se~B;d)9==iJzH6;xtwbb zOPG2nZooQi+;KilcF1}b4+wJxFFy0>Ef7_djaS+H4yK_>i^l0d2vANUoMXjwtaistiMUToprQ4Z4*gEl< zGI-{w9&h97r(rq31ki~2<>$GVb*m$tSApjYY+nZYKDN{O7?zQOoQ+gCv(U~B$!uIV z#DbSeJ@9YBdz{ecv^;3^A47RlxXqbVfPFpP%AMgqXbD56W06ICZ|_G6wT_vXGpeEU z4Mw!oa1Lj2t#a9)ub^HF;TV~ZbUUh=slyQTX z7RUN{H*(JusFD%pzRqs{4v+XagX)41J6xkxWx!l63u(umiaoM4@1Nq`+17PaQp~>n zyJn4!_VpeK;v-|8i+(E#z2|HT@=d5x+oRE}%crz$G5=uWTMqKyyw3HN{Ol?zprm9h zDvnVMD*6TguEE9`DmvreN$EQF#{=d)^|BAd>l`->Q=H@gw`H@_Sa@xZpU7jNX>fRy z=(wNUi;u)z{NeQVtl@Sb+2z%7o8Jz@+lG8x+<{d+@)&zE4(R9eX5VdWYj+|7HzT3J^t4OI%+}h)oV5_~DF4|Yh z<_V$zt9my8ESG>nd_4xMQ}sq>eMd3jG)F!q?@=1K3DqfLUH-P(Jrlct?jMBZo2fOa z*JeuyEjEr=yta{l5$m-KvD$Ur_`sy zg2_XGb*^gM%gkz=W9?Sx0PQS*q#Z0H-DWQxCOnURJ@isJR z3dy+=OL@rqwX2jyvBTw4eP{Qmi=v5`)8V5dx{yA*+<*G&ppioKf6CQ!W&D0A;UJf7AMmB57~rxqCZvplaIj{;qVyEcOMbcXWdh1zVrX~%$ly6t5|9n$^|Fo#OaCLOu1)Rb@OQF075mdIA3=k#V9*Zr$;EO69|lj3wN zS}WE9VQWPTiu*C+;eL+9@#B#*s9o9 zi2ITcIU>hwJ&v7{FY=+s9j&yZdazO^x81$=Uf5!G_-(TZyuh>%LsU-~5rNEsa)}1PK%dLpt7NhMSq$u`l+yxLgvjA{u z#mWwOTP^{bl=z{om?jToC&|u^E+-)z_@gZeT_cDw3SGYS?6CLt$7E@``f;_YQH25e zG#_uldvw;kWZT^hT!E6j!r=p~gq-G<5wJ5*8$lv?^^gLEdnT6OW~S-zSQTPd9I60~ zG@ttA>FbvgROrZk&`-)-w3Fb*ro^K<6n6z`(FJiJ80erQzK=(`7O>${lLBtz`4vNi zsSsT}M*376`oU(tfUNmU#_O165#(Dd6o`QnB@ii?(}#DY8LCzMWHYmHbHI<$9E+t> zZCj|v-jv9o1$FtYUNZe{HM~t|sfYnC1-KZF_6jsB($R&~?)}!G9*nu8>YLZbiB{rD zJ!y!=o|M-X1U#(8LSwfT#TnaSQlHKzIENNYgW_f@$~Q_)(ms|PLagl4B*`XygOw-L z*}b7gdc7A}RKRdki;Bb)FwPUf)7n7(-H6pmH$<5bZ_OjQo$N?`NJ`3IF|wPJEfXb7pk! zynzqf&IRGj=1LTJxDJ03zi&E(2*%lN&Q^6l&^QAIU0*Q9@Ww0h#au*jNgX#z<|set zGS|X$>(w2Dn4SI(G8osYu-HveFJ&auAUSF<){$x!#8vu>bt6~|q#64n)ZqA{J1SbV zFv@{l5ArNU_K5Jw1(^nWp7wf`;CZ<)WRr9L&aZ~sSEOR*?-Pgrb_i`2#?o!3C^v%2 zDNFM)*Q`v(%6{hFy0VB_0{gMTbADMgPF&I3z-c56apG$Y3L%!-z`&l))R$8wfEjZ_ z>T)J2j_sPTm=7hFLll4q@81^**2AvnXCysy@$R|zUqy)<4uA>%zYA&Mqs=H)3j?B+jYbmB|v*W=lqp*BNFYC zHgFtDl%1VZx0`>Ubb)3;Gn6qT^eD^#regQx+jVz!4>X3W=7BCs`hmZ9X8`+0J>P?5 zBUK}n$YwT#A^d`Xe`iP9o>)nnnehmV6M4d`5UxgAo}tp-t~kSFecw+4I>#QjT@QDu z1s{3cH&%SOh6yfeiwmxVv7J+MbO^Ghf-o^<$oy2+Vj!6uzNK%jkKcKx@$wwLK_)z6 zv<++mb#IQusG_dn3{!`}wZ8%8If9+dnbS2{|9K%8vMzSVKd${m0C$`^%Bc%=%dA~2 zke`~WO#jZd&@~?Cs=zDg^_z=npq44(w`NymKAuM34cjBky}35rsIa^2p(S9PpKvy0 zi&M9D4tT+5NI7UIjxX1*0=o%O|mK$(ctslZs*PO7E0+Lg@m;BOjgwoZ}5xNY?@-@mOW^6vQwTv zu5Hxz`9{=~wI=B2Oa}DsQsIezvnwp)c08GPxxt=fZ4P$v&Jht@X;O3lc(^k3c&q;G z-ri~Wy6DqGER*-m3~6Gq;swq2q_C=KFd|shWv&lS9Z1%_+`R_b_s_y{isy`7DF}N;nZi%j{4B%_7MRv zY4O45n(oSq`**PjKXMrHct>IqwZpL@&?y@^_Vs(b9;gek^`BN-QvA=!6yzVaAMFu0 zzfd;VI$sNfQ&6$`VLTL58UA+5w@p$m)%MK`T`DoIU!4P%k9Xs?{pTSS=@G1{H}elU z8}ctE|0#{jK9=@nz&#^6f>sP-Ha}XRhyi#6$w`5remmTz$9SdM1R8)<2>*+#M}eYC zYe2`7o-l9QY1{qP>Fsf4jVo>Wu`rtY&xMcGQ-Ka?=KPjQqcKct(k!AXEkRmQNSEwy zby*-sS|Da>Dv)QZTs~#E_AaIH+5#h_efxI=Ft6dfP4e{u^PwV8hPla}Kf0tx6?j#b zL*$#3!l*NqkP%Yp`phj;E4%F4wS!fbD;Sw}g03gy&`38y+p_=hYJij}T9a;f%&<7W z#d!B}me8^(Ef8snoz^CT3om9h+1@^SR>+PSSkN?4CAPLjIw& z7~v_%W)jnw?w2mb`$KdY&yhGPCILHV%=`7G-=9{KHK8g15vw5#DL^?4B1W<}udVR$rIAE$Kg!U&fz5@X~ zHO~@84CaD6x1DExRUK^&-{rG0z1i|uDs{kQ+vj;7oAL0u-o+PoS8Zm~)VTkRmI|oJ z#yEM`f}Jrf0z*AXU|6E%!R(I}^-;F&l0UvpiR+IESS$ym8zok{rfW(!klLc8w%tUo zl*+%Y4!jQ9=#dO#lu(KV&Y(~#8XkqCHDJKPU)*82n!7dUn|8-UdhT#5e+!=v@^Yt~ zAxv>=3_ZawOKzKmxQw9>WI@hvc4?^9Dez=#^?IOWJ1U@||5@0Kh9`Y^R!9f__RrX& zP9m!K?kh-EZLW_U_a`hyUX>``hK6cD0A?{A`oWx6R^&$kHNcaW*e0V5Q`#j#lZsi!p6nr!`t9sD01R{#1Wbijp9G7#EY_no`$3 z4r@%eeCUJr=R6cMb+deVHfR3194krOti!->{vlOb#rcpws>HN&NAiVC=#jalw2$A8 zhQ+R>de8gUA|S@m#0wc^*!0&hNQP#o1;(lp3BRJag(Y6b5eXOBL9D+rzCx|7trhF8 zfQ}y(`ZuRQIn;co+AcnC*e6H(gKcu_pHa9k(?druE=IjQngQXCqF=463C-? zfg2-ZpL!t%q&DCk%yCOo@>mp~))oGY2m9fLdU7^~(I+r>d|abW3$iE=I!4Sa)>`O@ zBy`uIbGLENcr{ zv!=bPD)jvL`^p5jwSq4E5NMNrGL)1Il30ls#Fcs8?=HPWyN| z8H*>6uw@}H#iX@@iif9)sn_}0{TSSUp&_l z$(J>)HIGgeZW_tNPsfD1J02Fb#PNi5qmjQ`3f5j*@YQS%FU60?we%!sepe{59f;Ge zp|v#+fCr^)vEfrjfBX<<@{)aCyUESKl+51wpNvk0J|ddi5v1e=4=c^r`=;fv)r%u> z2n(#|CI+t8MX7`+qxaAU;!z=E#Smc+8fvY5?_6m0VK+qC;E7t&1Ca6{DLEhAWq(m5zfnCmCz z%!T+D?`ZbQRww|cY{ZaBZ|1l=E-ULsGchB#gGVA(Ok?F?DJ?Lw_}5ZX29MZZ z6g-_t2f=v*c4om;K|C4KP%mL3PQP6b#WKCBCgmDGSUW5Sg|RayRfS&P(N?jKx<@Xz z(!I+eRB~o#Cbpy|)1wZPYXp1n6o+EPX5_rYwqHgm0QH-H#1DfG=1OT9_;XvV!2b)2 zpqvpQHs7cdWAK|~-JqiD?)Mu-1USE_;>K6@<4NN*ZrUGXQ&UvfYKih!aHwcurmC@s zsK-GvtqCDq-I-Y1m?5mJQe=Qs3`y3RE)I%4N=m@P`w2SGpHUn*ZPRufk-dS3d(iWOSFG>yrZSRjVJg>UYT_%8~tv-jThUu@26 zgvF(<{x-zIc^&NRdMh#5>mWRcm0cEQ@yEDY=loh%NuATB6wpSvlbI36Fr}dh#P}n; zP`A+K^*rt?J7En(?Xr;F@vgL>SGvJz_>)DLdRzEF>a&&-sqk8^ zFL@EmiN4io=)Vu$H46UEEsTqT+p$8H+LVz&JgxgHHJ2|T3MteJU~1q#wirxL&>DG? zf5Ct~2yzN!?=*=rhi#%*h?!;;J217Y9`0<)Z?A5x)16kf5A!Voa!PQNlo23qbhzr^ z?Pqmt%m@*`1uvuj2yR}vW77od9~M`-BF|w^=o0J2#3Jdao04#bFU4Y@O%cqf*O&yR zPQf^}&~faj53ksHkNtmc`Jz|*UXn1{gO5T-e!Ng$<_vYQ%0{NdiNjJ#LRz-x4}MSK z%$Vb12L;;>q%4&J;O0E;r&aP+$I(EQ1*@RlF=64w-_<;SrOyiyP$A0Ashjuz$bAA! z2VHTGxMLFMn><~R{)z!xpfYgk3s+i(PM0YuGZ6J`;(qO5GFGRr!4ys5BXqdG*V}v= z_-1yqL|7`qmPstIH9)FDA~XIvFsQ`Ou2YlWbhWO#mBivrn~?1<}n2h?08~U^azf_q}H<-=#$vf~w53NrDt%xrbo? zO&Xi_%_*1F@%K7nSy6DK82rRDRRCIPZag>9Q?qtEsYfn5)v~XV{}R7=t>ePmCJA?t zFdHg+!4v84fM?|-{IJ-t4s^Jr?M^s&QSF>4-SV_B8Ij)8GO$)n{W6-Bo_pldMAgcaS#Qb?CfOKeHNC@gnw6MqMDR&#mSqAz zec;m@@{^m^_}LWY%_+nvbbfHoiG*_;u1XMbJL-RFL~4AIiRm zd-hNr%|8N9a(n%zq3`*k-dR(Di!z8&N!(l*ANmeqfll5AVv(-G*80lJ_+Or38!*xT z4mydvEteFPucC{{D3Iolx^S0$w>MpED#5UB$Hvp1qcbX)n~%sTSR(Ja{sdgsQ_BE6 zW3hez5O{pfSvd-Z5-hE6{0ZF2;S`^I*Y*j?l{jX;e&cNR_h1)X%RDla!|%EyU1*-~ zKghERVNWV%0vJrIr##JO8g*uG49_}QA>5IUd^huw0gCv+vOO~~u?sW(snF<0&lSbV z)aMDc_DNKx)1Qi)?Y#{2)S_w-MiqY4X6-bkPAA@ik^3w=w4?HJqFp&5OK~6 zbLN5xl{Y(2cH*lnhfA3fa{QDxDrb@4BOW104%Ny6g?@c%n`mJJ(HA6cQaYN9zlqqq z=#wW@T00e5tx2PiX^0gV0HbN=0;U@tKL(b68-Uxv8*=I_^SD2-o{7x?QGZ9@`Sh%| zICx~1N5Qfpe?F`A9#DXVuStA_W2B!R$DWLZZ}%C>yn#E$S5QKwoc!wUR->aZ^NG-^ zoth{v*Tq45g$Un9(Kgw!<5w&3`)#=0b6vX1ZCR|`@Nv5qBFH<8kSpRQb2)Q!4Mtpi zaV|cIgUSrl32F7O-kXcOa+UCxHKY7y%lXgIwC*5MkdOXJPfjD|v9uK-ezJy$E#vOB zAO|pCA?cmXXR8QTj6%FfgZ#ImJ$+h)*xwygz++;0pmY4f&Lli+&5 zqU?v28_)D_om@+Y5TS#=N`YPTd3MY)UTq=o+RrDPkvZa#N1!eFptCD93De{7@>>DA zZpSH*h=vf_GyBoPGLhzF{n9oG!(@Mc;)I;lc*+nNI74=8x!lnkN(4AAnc>OsIlu)9 z%Cmf`%N8MOwwQ}Kb5bSt9LBDDxgB9YR;U9sv&T8jKb-kIavF^50}CX`6rn@q$9OKl zO4x3!o_uMoe*`{t2h%{D7*FG?c|Fm5ymW~X@UMzcQf zhJfb8<~pE)N%5m1HKevxDX_CW{><8)FSTMiYtsHWjp;|hxM7t`F|C$Ry$WilBP;b& zhSnB6{3K-7Pjt}|&H%2(QzohVR>-5ZHYHVv)b)s@({e)k^3@fC@r(-?V_JS48PGni zt7eOFJ5H;(kAf1%H5H`r$9GJoWGSZajr~Yh-lm|D(v{Jtu)rhwXU)#7AcGlqrzaeH zu>*YhiP^;}s=3$et(6iqFPXz##p{=it^d%fhSWxs1S@ZW^AdHu-eL1D`K>ViP!(}j zH$K>(1jwlLm+gI0qkOhH`tC3Re%&jk22<#kZiI3(qtY(r>-XW@wQ|h&^!_-{&C(u^ z7amaovgIl>ZJCudQ-ovaKwH--X?f-~U9D`!&*s za`%hWRlCTd?@v1E9NJaoC-BwNy=z+Z49##ww9CqW-<^lUzxGgH7+c^y@%~KaOSUa7 z-NiCCJvIDKp1QGk95}e|0oL=^1A^{^K7+aPCOP5>XDt_txC)dz#5Pnnaz0si{A;9< z=ae1cw6F0w08bK4V#pW0$mofD7nOg7 z`Yg>wjLFDNduFnzkZoMi6;I*U0&?S&h=v0mc&Llt__yoV{$Fo##mS*79D-l(qKS z`~FocYrLn^-pMG=3k0{v)+vW($hNcN`%SSlAcXKu1$%KP3Maw|Ou=UqGX8=VyT=S| z2RgmGoGe)QeO;w~%VGdN za~8sHl{iY^BROj1_A?gZOHQFDlKltD&C!pZy#~SMSFXZ+C$#@UnqL>cPcn@?8+S20 zc`ucs!R1LB9G&_m+>nky{`B3nt~K}ilVR38D7^$f%SSe!OpT-cV_!b-a@2;Y&Sm4g zny720u{V*EW|V1qSQHrxIB_JJQq{M`?Zj=>ut)hSl9I-B?9)d<3-saICY>S9QQ6bj zL-7`c+YII?D-Vf`_`<|2iX&Yr!xGcs*X(`w=Z+k(AO_AXq%}j=a|%C_uIsyD;fW7> zc9SG7^w2P^S&a--36H(;;*Oz;KO;h& z&@VnKO(?}Un=XE8yS5WnPY~J8t7b|gH5FvD#kO<_S$=a_fSNNKJRhaj9$v;MeJKa; zu&m3{t+OwRrYHG-23TIjdlLraiPmr4S4ws^>QrK~0QD+g51+W42jxPz-LY94bM4^N z1OGXnU_NOg5YesL;|*Vbd{x|P={0dkgy~J}5bRFn(RaOsWF#=FN}_5SaAlW$fuD$6 zG3MbM{=ltI#?MK|)-^fD0w#Fgo^dVP7Mdismw3R;K5xhMaqm-(E4AfHyH7xggktu8 zH>>SubsaGprBoXtNg3{2vcsSMh3^UG^BDdZ5~C_6Dw?Cp!ekBXqDOPgVsqA4hP}$l z20;ss^Oz zcMiqXIp5y4W^Yfdl6WXZ51r&d#zeZJtWrz>M8@2t&_y_hzuwH(=Tsvi*tZ_O7M|2n^HvgjIo5 zU)~yR7jozFm+X#7<^OuFo4TLHa9(s+P$_Q20F5@D%q+`MxP0JT#JCeYGk?1-Z(PO@V`!`tGDaQtwMMn2FkKo37nZP^Eg+# zL9H=5@%Q!Od+9DC=r7&Wq&>7BY<( z!w=h&`X;hQr#r?i40Pae*MDxMLciCh&`P@sDSW?D7C#zwz8^nK?0NtUd8&{hzYl-m z7ngMIe7FS6KZmiTqdq5G+bf{6<8S<&*laT5Qbi_g+^7_3n@p$Q>ATX?qdbuIHR6x! zDakF?IX5h3N?`;}C*uOUsMVH}z-TL?`y`?`;!tmZG4Q579tjs$pl!`=SJ3w4A{lclc1V;5nSw>TNIl-d<3(%zl+r2aiI>r*>i zH6}Ot5$3Ui3?r<|ZW#4XJx``7{PU4Wq|DX7FHPyjW)-`$oNp^aqK_rBWoR*-2VRnAZ@nJMo(Y4&bOTHb}Q<0{MgmiYkIw3 zmA6%7q$tg;fK?qEnGB0ei;NC{DWfSSm>ifG05C598cIrr;K;xPptZ3PfeRqf1$IU- z3T%wP4NQO-7#SFbl7K>NZ?BX zp^1^P!I7l^ENg=UsQ%*sAlAkMw=wB*g6KfkoV>1IV-RIZB;=uT$zrSk<3LN$CI_o$2-I4_u`@5RP0>Guw0o;Uf z`Llu#`>#Et)#aC7N@8MlB{(fH8CGEW-w23-iKzjQ15>m255G%n4i1itO~4=8cfQu| z)n9j_jLd(BG+0ZsjqL#bD`5do_l!pSmnN(*CwEn?M9&;lC*!JbU916UXW!nIl)(-)&_vPz&>8zGGMK$f$<&~NpRI3*WMO^!7D zMdGDFH&E2Y*rEl0(MrCP`t<>K&PtQ@mVY?ZR(PBZj)|ml4hww&ORnrtw@-aiA{n3a z6GYVcjMP#TjQ*;tXUE~j*&9m{!C{nw#4YZ*d`X3gfn;eIoP7DP3H9XFt_!-$3z$0L z`CS$G*I88SW;WKilGBIipxpJm(Z3b~Y)5Vv(?L_w>WAOUmnqs0a{b8dqjfKC7}pOo zj{T9@jbTBwqY+=a7^TRfBjLJnB9sA)82}e;<3uXQkpze~z}vb)p1sE*XxtwF+J%U+ zPCWh8cUkntZYODExVE_>ZFNs^ER)i=(H5@pglxvBh`dQx7T8>Fme<-zHyr@8VnQ0A zHLf_hZ06kdA6)~xCAI)2j6YM3pc`(MvA1uUbs~8BQwts6U$i56F%o+2l ztkg}fjMpIid0t7=F>LW8yaV&AvZvq)j*~HE-^s9d?g1Yu(>E_JUZ%-`KCC>eNNtI? z4=*iFL&%n#rUjasbd9E8$4MC2`>Fc1tzYF`CQqNo9TC4X3Q3mL*iqEW-vs@K!56)q z)sJFz6_}TRC>L{Tcs8N2hK)N9Z0FBwkc#v_g+}-v8YQmfVn!vEdTBQ;2G!G&Yq*3` zmN&JB7tVyS;-{@O#kz0X+$oKR_7#nT2U`_W5pN{1>~r#{ytN+IC7wy<4$Bpf`7M^e zJCBuU`$Ct0heR+hI}I%Gd<|r>aJ|d?ou+=l}Iu`*LQ53GAT1b%%qVGSrKq4M)rO$QN{askB$p53I-kdVob`Y zGZ1ys6L(N=Z#}*%7h+S0D(!M<)Np8i71;)9aSY?$!~qU|i+tae4;M{~0A?;eP=jL8 zZvL1v<5{oJT^|BWB!e#r4G zQ`X4Gw4nY=Nhn-{2(mrJ8jt>_EC#*sdhzRj{Uddc$LgST6?6z!qtG&9FY1^QYCQO= z#63aRz=P$Ln*?8}j8g&*scyl}g?Q0Y{s4{LwZff%od?S|Ci&z1Ax4R18F_>&tGvg` z@j*c0mnqIGUjf2QWAm3&F8wXqi?WIumzU!cdUT>^~n(H23vE4z#S2P{mXT%mC zC>8myZFrk-^lOt)Yi07z23=H~=RbE@QC(2d^sv`S3kejMW9{}<9AXJlwP6bZ`e&^= zWagK9SO!QDcK=F0`uuXM9|g0-QIJK^6LHIB{B(&(A#~^%&Wm-tetE<{1AiHW`Bc3-+@dM2qLbnyF5!`?WwWKDN4i7hBsrujRkxmUpKdA`TQ zzG6~r)Xf(_QmMoR-d+|`!|Q>;#-H?F0Op?_T83TUmI*SW;f2v>XF3d``R@Uz^b%RsDDoE5t& z09d|?R8Ing-u;v$jTViHRg+hWow*()*t;XpaEWkK?heBqVHrC={R;bdzBQHJ*}7J0 ztd6E(YOm;_Y9YgquTT>WF6(>P?2O(?EIYIr8e?864@PNKAUmxj@BV+n*>$+_#mBof zSaoarv+H9?QB#%}Bu|&Q?SeLteJaYEN!8oxFm^jJA`PO&TYL=Oy4 z_1tz=FZ2y6{;-W!dwn@`pYk&sES?R)0zTbhN_@-!x6q%$LhWgZ`AOIcj2bs>I>F$u zkp==T%H+=%4Rzx*jmbK@>A7+M>c#rAfowC%Y`$_&J4*z=L@g8A1Fv%f5{HxV| z+m7U2i6aku|hr_*!0#Rmk<`G>}9Guim|=aKZU z{-xx8enuW*_y;z`GiQai3osLW=OQv4lvXuj(@jToMl4)tRZM;;=nz)@%@_px5iw%# zpySyb5nUIPi$ej`^rY6Ro6R0q9pas!Q`_EJy%Rm-un0E0%*%G%>4x8z+DP$!p#~!Z zY0N4BEShJoXAkP&Le4c%(ozUC&e{l6UP+2_aZ6LGV>L`!DI0(_3f#_$*%}G%E}y&H z8rju_{n*k1p92-K*gHwa1Yn1zN|<>)rMTU4$YOy0e!q$h-=pYH8oWGJS{}H!~DI z_XBPS=Sd^Yk;M$C>zx;zYLB6Z6N**SilTQl6^Z;i7ahO;ycz}n)!77cUT*-V?`!IW z!GrieK0CK52FYe>gfgR-D9012`qN?ARJ~Wn6n@g@~#O}ANXO%c~zZO+iO#QQ`5T(82v0X`cU+c zNBFn!!As7RGu#w1dyWc&8dGf75^~BAL{qRQKTYoDzPTGHb0|V`O=7%wwa43;1?@*E z>ZbP0*4lPlicq@l?xReQJi7a!i7MMC_796FOJCMI`v+g$xyg zags3mOHJMSr1KJ+9M|%ds3ogBz`PhE0{uh9RZk&gMkr?xeq0ayLy|D8xBVvn})Rr9|)59iT>gl z>;lc=-){E(yI@$e#~x#Z(4=L>pEinrui)^yT=F?a#vyjRoOHA><=s_qsxwu>pcH;h z8M`Ppo|AUr zyakkvv_@n`u7hqu9#}l`hg-^jMa-D)tIb`cwuOY?2m~6E1mEu|NzHR<=fr#6DXY6Y_K?e`DmsZ{l z!&54Db~j9awS!P%c)H%bd<8940wQ7C7vZsBN1xto92L(nU4mE8W^QMq0SMWp;xz*P zpr`T%_eac(p0A+WrHZtQg{SdADK}leg-~gfBSvWO=h74aQ@nY3h zJPE0GTL6MYP2imqJ2wGc+pNP!waZv_0hy!jr#bd#6N7FSxL2QdKO$FO-QGw|N$}(j zU8_}rGIkjdj_$H#grA3p?8ePZgdUz(V3g7s)xGa_~@=Ws&ky?(|NOdn91{n)kFe2H5M zTYC$5lJxAS;k^MhL`pGG;yyt|pSbs&-Aq73nv2gPXZVy3rS*@b<*ZjLo{Ve;YmU5bYmu9`O&jxIa;)mae+ofBG@BHL& zQzr%;CS$27!y&m(_PMa9?Z90a1w=f*0QAcdxBFMyxo6YpHPlbV6)9u_Alvtw#A>;a z2bo*tWyIrguE7?Rse{A>nf6x6f|!Kh&(7*_h}qU1ya(X&ewAA&r`l#c%W1Bd8rnC5 ze$&K##PL(poE)%bI_)Nw?5@AF#c@2Y>!(&1-5r1M`7*5hi=c5RH;^b{CXV^FtetUV zLnd3O9P5!^s$x6HUyS}kNU+wJPy1}_wqKNdhB4FR{E)U5qFjiht-cgiv(Y)E1f5gR z6XuW?T0v{(m@m|hO=m-?<{0gxFIxV#G3P(53K@h zqje2Wn?TAIDgP0CY=JHMDc&i&1zB?`2&yuhjs#DQ)_q1LF=^4>2iUb|ZW7KqP5J87 zok+U4BbsV=^4N<(tz4MAmip5A(-u2nPSp772yXlj3SXo-tOl~^ zMaVxbZiMV2FK3JXwlBH3s+3zd7sFOVfA#@CkvxWo&Ka~H^NUQvk48Jx@1dV? zi~tQ*y%(lm+3mpe=wTl!>bMeLc6XpjvFlTpl4ZQb@BTqf89byWXSatgdJ{DyBxRwV zzF`R0NkD5235f8V!Da#kCkrR)!tWC--)0sxqaYW9!Gkpg^;lM&l_&g5fF5cUp3Rsz zOb&I8n2Gegj!D<JVy0th;lw&>g}93Q2$ZUghP^jFoMW+9zyMvD7Bn<^i{mfT63aSF9Ko4!}*YoT8Z? z$#Qqn7egGU-IR}uQPQbFN7}x0v6hy;^s!86Xkiu0NnY26q%-?O<7XKE>n?c)nL`F= z?@R|;w0e4RUfp`k>nT9R|FH1GNoDAFV(D$49C*bFi1nVW(RY2@1oBg2R+W8KCDocP zWPJ@*$7Zegs0SAqUQWl6HDOrsUqx@wWmf7@aamNEb^MZKpB+`2s8}Ql=<-{lERXGt zbK7)T6<0s{t0{oJE>Gbc|RJq|BhC&Jq+vEKG*M;*OsuCEb zBr@Hs)&Oh%k{W%!a10(U?)q(}8&4{ikGn#)=xn_T{cQMA#VH+Drpw99 zL6^3_>J@WLesVCX7*pZFc_YX2)0{@FLZvm=^TiYL^|uC9GkMe4yTY07?h?teCqc9! zL@(8DCcM7fbp_C9M=E_84Kp0tzRJ80H&HA?OA3i99Ufm!T(7liQ`CPq%CW2vL8u6w zs!dK75V!5eP+J1sBf%DFEw)x}@iAf- z-yWzU60l8-Wp@n<;mC5)j%sXC<69#rl)AdwM|mkJ@?%X{#wmS?%$kJ8uFXkI#Z- zQ~u%Y=Ay8;VBLG{ddFIOQljsIN`)p~pcL9xCwM-HFzVtvQgq>?0_n8bR{q*L+@4zwt3XGruSOG z3CT}L5pb$AtnFv3&;LQq-;~JlCyms4|(-o*&l z|FB|F`$i}EmLCLtoa4|c9#?=T#@B>Ky4yJvj0aCM<-gOOEBlvMow^Sv`6#k#S)6M+4;eC77_HANXQ&nIIgYWh zry27P%>-rejEn)NBO84|LXdqL8dQIHuo5FBI+atLACJM+fn>AjC<&C56koA-IT<;C z%`iE!{e17dzQ1qileU$HZn%u**P4U9sLnv*2e~;V&%}e3#ZS3V#@jdG!yh%hjTJ$x zI<%o~T*vv!1VbzbOCRU>*FGXesOAc^@B*M8hkQJQgA!gMZ{3}b&-BN$9jJtC05FFV zwh&^o5Eq}-eAvz8nJG*AHek5*mpx1fOh6B7(dI>H8JXlDL5DUEx%;KNQKp%7KRh=I zlt|61Kw?K^eDXk=-HSHOx&$TH!Dd|!TdaXSN^GYKkTFO3QaA9;G#97(60ZJTJO~=F zz!_uSAr{&!a?vJ}N0a}Q@&l}>${!Jt9j(}c{m|06e4QETVMIRQa~2IIOyF2~Jv$@y z6wH~WKltIy^TRwvm3;9g{R7b8d=;6YC6WTliD_)5I zFjp(-q*q&gGBE{@Q&GItcWs1G<%8-l)u)be%-h7oLuw8d1eM;S7#8znLMq~W77be& z?VN!&+Vai2z5692tz%k$(=K(HocscGUgYlgj3?%&E`l zIz(^1f6qhq*umi5!u4(byioXmEue=y$=#d)3~y?Ie&e`{bnwi+IIN|ecU47a#~~_l zj$K*M)`S_9Yejp6Qt`292i-WK`Jaja^0F&v#~~v0%eG&(0lH6U6m?^daO|^69xWqd z8;9C|E;xoeXWnalge8nev3f{73ww~BZp%)`1BQaZ^j@O?L;XJFqls+BGd69_hEg4F zI!8rhR20sTj0ElPdh&M#d)1z}>?WUFHd%*31vZ1PMd z%%F@7x9_}KV$lG!OG;b)<$3kj(ZR8=p&o`aq)gFKOETJMbl{EQ>8G({PDVgSv!rlM z54&!I!ja`=Q+S38B%3=VH@tm+>b9+4+TBY4;t@JPy?zr36{)SV{?kGt5}87Vy1CM_#<0*H@KfD0;`9iYp0xBYDA!sOF_6s2R4!QmlgOhg!>- zf}xIEf6m>=3xz?oA~ka%61%Ff>JljRYmx8#eHG8a+`R_H51_iE-Wx|-xI@}KW?C*x z+;5pvh`zi{w-e?I8i$+%n9Sk=6#8_c(6sZzlX|#aX`ftjcD8n3ks6-611Sm8X`32s z0Q+l$#QMcm0p>?7y`kr7Lr@a2seSd2O>g3(SsAV}Fh>@yvoC^D+9O`1^o z<WOngtyZta~q7+@$=RSDRWD3rAv@0Yh)mXz4YG z&0+305@CdWT-qL6yr?XJaA|zYx&5Sv>vm}ca_PgQ;zyAOb}(knV@^D8%{PP(1CUTQ%yCe$M)`_ zIWi0mA_b|Oe}B~^@h8Exo(;}}k0}dazLcwjCwtT$ z3Y;Pa1h-phj*9L`%2We$RD%=Q37$sYlrxfQGv_E5o5q#V7;fq zQOr5?R-Sqd-q}^euy+m+2YVQwBAM4jb;c;>q?jeX$ZXX^b_JWF_21m21>6)_UnFDu zP64*={Q1G3`?*P)Ty+AklF{XI{^QdUr5CbW^bAYjqh~{$ipdnfX#-YGEh2^KPT7Xc@>$fuH?wNqMcT3vuvuW%@|)sQw)6Dq2)EL^}t)+dBf;_$rT)4SFk zM9DkT&9eQR*HQ|cCdbWsRB+M=;^)V&D*7G4ynL$2qSIpDY3s)cP7RM`c7gJQm}iCt ziHTnQ6h4V$*HkN}XVY*hu}1RA=Bn4Qhb7H=1h=G${@12xySx;-JO*)Io zQ0kzk$ zPe;FDl<@fQj?=~7)Nbx5{HF)}y7$0lz1?B6_MmoSj@NdYq8OgNhj2(0{=~A<&zQ0G zzxjwt431IhAdJ=H99UYHJS`(W{+U#lruh#mV^s}v7yL@Muc|vT`gGOPALt&ArLub* z>|jQu@)EZjw*r#+92!H@J8*#-;hrblzJ*Y+_1h}8o{OH5nPL${%(T`ftOgcGdg><4 zeUkpxm=k^(ZOR{Fa31mN&#n-SyvZ${4Q{WcSk@OzYH?J-FGx^(Jia6A3=2)Z4aLf) zfpMP3DP_$qxS{KGHcf_1_s@;2kjvVn>$RKS&?Z87_e2;x$>_qSqJVGtm~R;g`CFi( z!NH52VN8&!>o}yx&2mgI#2e?^mJ=6qbD1c%*l=GQ0Q)>5z=P4V=7wanRm!Gvkm@93I_OGH#$5V@6@ zgp2k2F@vd!rS)E}SaRDwJMdN}=ggl)wQp51b1xqbK-+cmgm7c6^x(&JGb~6GeI!>R z>v=P{!sRo&Xj)#gcwe=rH%sXhPYDti(XQGN%S^CEMr_E#2|)^-nK;$eiW-o?SY4k< zv=Lpc&cC3Vx6h@Aka(3GBJ{~YR6cW|k%OWV9b=CwyEn^ldynWnWr0(ibd~_HTL# zd+hQ5_h>0_GGY{?+W~H?t&r@%hq-D ziA&k+y%yQ*X%xzh(~;oiBP7n7qZ8~Vi?NAVW&w9ZfptN>7(N<8uF;~`wr;cpNTFy# zd3V@f#qBQ_)do2pOYDcq(dRIrpQ;R`2p@fuR+1q4ya`ia%QEWZpy(3XKioCyc7^-s zTgw{(N9XCgNe&A^>-Nt?#ELBjZ^_+PRoh~?F66|6ZTzxt;MnIAq&8HHRklLJFd*Ob z`it53im~C)vIT$Tt=s|D<8;h zo%__JWF5usa*YZJeh*wN*>v_}Bs3cwqw%78c_ZuhY3RFkC45?4M(*yr$?egL zYQJg=oRUVO)}FyDL2II**tzGeSj`@*;WmIS(KrOdR0XQ;br6H(`}JsW*3g;2(o9K| z9o#R>Mm&r`uhCyATR?s{;*tLwYE(}yB_dt0h`Z8ffH^(Gqz#OOs2L^?_;94x38r}? z&fA&hpDabnHsXAooNtjRtd}{0cKi7kX(9I;`#=vxI4kK{)t3rVINrNm5-Z!Zq1yLj zzdAuC_E5^zSXNGBQFiiq=|Lnnu3Bs4E{*8TkV^y*l~He~(bWS>@>=Jx_Ox9vOjSBo zcqb01AEBX1Ct_Xi>jbZV(f~%EBCOckWGLL^bnz5)@MV?vAfhS3<*L6y%Mi&=CpPR6 zNgl;j(zH=s+P5*}{J#A7;J}PHOPRchj%A znfNx3@XbEGH+D7zuD~7p!^HtRrM>-jzcTH)vG~_?d!mch-|Acw8wOZw(fH=>v3%;m zG_j2WM~l&Z;{s$zT3%nIIH5?@3uneXF56~q;dAZ3&7^FPf=@dEdm%<)Uq(jJn#6hV zO=K8p6(jQlbq>xi3V!(`+47LtR{ZgZF_O3YHE}K{-aSRqjkO+OrRB~N1CkDLTtSje z&1evb2sRRW%sSh#v&*Kf4CpZ|dm>~hua6=tyVN}H6}Bg~aaQh>_Vb5WWIY<^lf8^k z1#~;$??jm>iT6Et?vxl>(1A$o6>e20N&ajSNvE{RX(;LR)&ck?9S~+4mG5-Hbs+fB zj(pavmd?R*#*yr(|uFy7ZJ@OXhGM()%^+k$lh(q!pDG7IvSz>-W75c5_ zIj&|Fdv$qfj^HyF=xo%VAw>;P)9d+u4p9HQB$>pIz=jn}aSCaNY;tJA3nn8N#hA$O#hTj8X= z_Y-_bV$tLy>Ho^CgD_b?7lq_5jwh5-_6HOR2H-TM59})iilBgS$>#BWh5Dtfzjdus zAuLPD{z;J*E@g6aBKW1|lJ1Ya+OR0jD_KEh zZ{4vd*KuIiill%>_Ky-8;1Gt{b=C6K8dv%K51fC^aYi*Xu4H*lXzXHme*~<{12k7I zZAk$DiS^*-z3aK7ppO7VTKcJOgR(Rr4~=5TFUiZKwkCK9w%pUlIuRZLX@=8s)Uuv} zy698y_J@)V1s9x=Su#$dCik}C7Zg{KYdtsPX3sRbZIE~|Ykofns} zfUv6E&#Db^Ei!bS<@gl8I?vqhxRnqsFnSTTaD`U6rXaO< zhoeJ8Tn=W|ycT`c>Oy*XQ1Zpp%hf>>fAQ(#3^qfSv z_dlvqJtIkoUt5s-z8yUY?IAlAmfUFqk2urqlk@aI^BsaE@!Gy$A}G`op7#l>#-!r~ zSn0|3ujm4%Z9UnT%>BNX7CB(Tq4@!s-ePnW7VSR)WQ2ANgBH`_#K$6E41y*hhLK&O z;F^oNT2@v#U^0Ac;{g$XsK6Q49@(Sd!{$^z<8m35OzjtGiBA#UIu3LLGF;#Y>3xd| z)JN4(wLl})cLaTGq#WXRZQpsToWN3(Oyt;gZ?F8$!D>rymqV=@Ti6rGg#X3J(G- z;${Ne{Xg5T>ZbxkNYgT(qWgNHb?1{PvG2+=bSIHY8R5$RY2{tp!@!21*sbQ15A`6d zMcbw4=yEFt(7Q+*Nc&1~^+zXtq!A)GX-Rv_Tz3aZgZ7V%-qw;tNM4O+z;#IJ|WXP7uk$6;TP z8|KBA)4$sNy!BrK4KClmup0zyhWvX3S|(l0#6wB+rj;}clD}S1w|>_e{17JOZT(?^ zJkMZiSe_a}4p;%X&j4&UnF>rkY3R5QA8iTa zYv!L!$JVPU+-3mK z*Cn#7l`_z^?ZJ04i+QM7CKeR_rQOl*5i0HX`Iqp-kSHX%u~{=xfpq_k-TZHSMJ`aV z@pb@iuT1eP?IDP+yV0ll92dFA-X4>RlOvQYq$;gu4U<)O#ls&N(ALXIl6rm_Wm*eJ znIHJ!r2qQ9%(5Eu%88C@^|B@EemyFZUnuSmuDDd1J8}ZpZ|Sx+j31wfJ{_7x$he~E z23st`CmY}(+9BV3pF<=ge!2OUcNdk2Bt*U3mUhE=s}}iQxvy5Y3~8kljC=H* zM0;FtzscP`-##$~i21S^tUU)?#^Z*VY-LUBsBUE>az4Dj7^vQ6M@dmfFzLVlVmwoa z^2Q^X_#v;alLhWz!c>RMz;9Y3dN}ioMp1&-;WlTW2ZlY=cnde*6KriwA)`Z`9G!~F zUsIb9_?ZzXbEMbf|IOmYN@gr?%p$a7$Ka~`XBVWWJY=uzUgPKQ2ktYzd>p=%ksEyX zjHdVZ)UcFU{^yN<`tQERhI~I9gwTyc{-7?~s0HPZ;WNf(&E({a_L>_1X&M7f&peQ2 zf>G#=wpBYfpp4YaP=q-L zL=m{I*bhCk`X#Bkpi6O%IfP`6-wh=2Say-CO#N8Gz)i9r%u#D-gC~T5M8OcrnclienF^E!jQcImb@1j zhti+Hqi{)kZK#3w86O?KQ-;d9wd`(eT~YLsR!Neu-iuTHY3Ot#@SnB-%zbvwLjn!i zTI7!dBNSKjtVKu-7fu*kr&tLM`}mf(ql=xOv-l&uJO1wI9f+e=t43rS4RdRuw95O+ z3>4QzMdjyxB>hdX=1~1U(EmbpG>&Xjn4Wf}1l3PCRkDk0@IU-UJx;(q6%^-n2D1gL_d~yUPr~r4u)JLuKCX@7D77 zy~g&@IvdBP4#SAbW&?ZrtT<{dw9!VkhrVUMrietjt!(!J;Mox*u)1zRQdJe_UYG|O z)N7qC^c@ix4iGj30ybc9fUxq1<~b#=orAB=cQY9=wGue$;XIf>be8@3=MMM?sSFmo zC7}T^jZE&Iw8ifSucPD_8OX4EgBPivres+J@hSmB&>|9-Yz|b#AT-GU7wNapfu<}e z;vK$P$FL`EC6R*aNeG~m)Ke&5<6!&ANOQkO)gQbHP_qgyDIqT>m16osQx0?LKoS2qVEXIB(sZ=BNbP+;vk zz`z(Q9zuZ`NsVzaMQDLKGRmMt;9$VH@>f6;4rLxI7C>IMtVCnrQlRxtP7rI~pFm8m zK$*I~(aErff?z^7LYAw2Lv%U#SHLhR7bHnCQ5Qha%oOg-fzV@kM2z2@_(vB5pP2A$ ztj}MXo=-rlzd9Zizb$gVw%?o=SMQF|$Z>zbjU4PxV3@#lbVBwreoC|9#s+}@y*svb zWFH2I1VDFu9YYrUR1w4f!?U`_ytc3`w=zKlQ;OzZ+!p z^TqD<(Al=PVj3W}SzzBL+-_S4{yx{IcFgya?>M@5gCK$ptP80Ih)j_IyWwJZ~vZ&1HnbvN;7m%9L~ zQKw-YM$G_QrPPEPM!ynKgvl&(q)UI~$BWTweCnmLfBWZcjvAe;HiIneMD= z9Fzl(Db6nv$D4mH}r`1SMrX9XQf z&{eoTB$eplr#QNfwBB59suta|+lraTjTwZuz~i=G=PMy{MgdtY!+d z{r+>*5BDVQJf>ZA);zpzdt+fE9KZ4IUe#)?pyA_sHoMQ92}qod)`(e(H#VLwoH1zG zkBM-;e!Ua^2H-)4x^VKTSwqQgDga&6PEERn`2MYE#f2E=fl+$J<7TouD?7WOZ0wMO z4}~r2YA;iimQZ(na;r-aT+ddA_r5_b@m*y@&u40(eoC|wZgUT}SA!Pd;{X+~?XiQ( z(nD8IfayTA>$)btheI)Ky)T z^~p`sT~JOaCVLS(twewEstUpiEe_}5K_{-$xLSUph+P!39SN-67`ho^rlEUa#s4u3 z;TtBY48l`5$5Lbt-iubc19V#ykPvF>n`~X^hqAE3m0DK%*yHge-!HV-qGT^|Qw;lL zl4ygMqFzLl0Na6R9-V>Yb3h6@Gdzaq@6ABk50Y>u?XosF~Sv* zPDK4s*zzXqkboz>(wQdF(^8j7Zg%qd*0owPkd)S-#rff$7BElegLP(W&UHNnbb(zZ zEIEr+Sezp@JX425faho}&1C#02^Z`>(|yNzyF?h$iY(Ds^0pj*v!l=GBQx*-uCJJ3 z9dqK-gra5p8uZBXb(SS zM0N&=!zv>QQp$2bf9apGPTeOYq2^=qH3_pKwh`DCHtLmfsZl@udH^j& zQ-4|}l=~T2f-jf52{wRe&?G?qH)&-r)|wpG_DdL&pS8 za2AJWgJg0r@`_frPbt~w9FNccC<(3RmC}r_3sHe=3j5D{n$1?)&@RC^KRn$gYbIU! z7NlzMx}1G~&h2Rl?emm8i|&C5U3y%fAhL{Tme_o=coU632~Y9aaPwAv8m1@@OiL42 zD4mWj`oM3zE>;U4sNP?T6@QDeE#*8vvljHniWS4*u)FPux`nL!F{!lnCC{&dg_S>a zZfUO^vb)&qvu|WBzAI+sT(r5G4Uxz9pk1u_dpg+bWVWzDATBVQSMsOI<9;~US;=IY zS>7GY!ths1QhvF5X*sRTPt0K(ccUDua#BY4;x%9h)|n{YP)2=Bnpea=Y%K`Pql8N& zCqzXFszgpRUJ8{`9d~@|A2Kz6x`;A-`nwWJ-uhqn;VL92|4JkP%RPx`fUZc)x5d<$ zNP`l_pKv1t|K@CoP4qdQc-+? z(<3iVg!hs~d)M1JbX_fJtbszLBJ zpMi-BldB2D>#U_80v_a5N349 zy=V%oV=Wa0v0vRu*mW2*G zO*67Z4yKd#HzSu9%s)Ru&O9p79ZT&5>@i-`YK|Wm)d)h{(0%@$L$+0e-{w@OcT;v1a}z~CFc|Fd&IqVn2Ii_=lzoY9 z&zo%OdX98qXy|ebmqVY8JX8sEJk7m3^=44gSZK)HYAb>^jP>Vbu=LSH$pJp|Kv=vW|w=2qcTSXx(GpoMiV z6@#-i<(kO}=dq0b7}#l-o8EYL2cvnz+u&b#f6#8(t$J0WM#kLqDMpAw(A_Ng~nWD0VpHQ-pWxge4>*KGSPk$E^6_1 zxW!^YX@T00Aec`}1&R=UQ!>ag3=S?~1v?$c!D+@I7ki085slAjq+FFae+BOnicDMY z9b2Gzs~8J039T9iB;5{}*`~bbkqE{axP~))&NV)71dVG06t7k@gTA^hW}q`G?MSJQ zFEJ%|#oZBPU3hz3pewm%1yxp-;>eCASIc1E)DY{aSVRTUA~b2)Gen}3n)W&S0n7O2 zf4FJH#;-TU0W)!_uZ0mG1;da~YT|fkt22Mc5t2s;E{LstG5uMJ%=i-`f1jW>qm-f4 z7HL`bF@5tm4OZ)`TIOtOK;@(yx6GuukcyYbHmnZ@j7gK+8z9X^hf^$yRO=noNizga zbprkKSg{XrT565r>~pv`uYwn;iJDj;pKO+K5B6!q-Guw}zwH8z^e@NO11xzxOqbo~ zbo|9&*sMZitb+PEE5`s+2fi!32A?c*jJ?}2SO!~?DCYe;ge+t6#F*hGrzCIGhcVL& z8efOhJM6cXto&rcg9~hw)$UK6UQR|iB zbn!3fHeTda9_=`JGp~+6i^{^}^;9SocbeX1Ir}*Q+zv??2=}|@s@Q7C?Wn3lb>c-0 zl2tT!_Ge~Khe2yCJPUNJR$HkL42~Pa$`gcU9iFr02wHW;DON}3xc)9KZNWuA(l29k% z77f|#qe4ccxyT|(`oBiFEVSY^)~>Wng^hDv`QYeHAl#jN;8rWiT1aG+cR;H-a;+o$ z&JE$?ESv&dnKG|flc^hX0~qY+*{=g1iS&6O(9l zCe4hozN*80U7-SiROYpkMxiRK|Bk%K(9_jdTWViuY`~!&M6(o*htI(W$f=0LzNC{~ z*q`imDKGy9?)G4Es=#Z&WBfkYPTWbG8p5b5D@(IAv*e6IwV&!)(1$@=B0YTvJ}L7! z(Z5ohC=|MtNRNQ}+iM^3ES99hW;DDoQQ_)f0r0Scob0XfcxfVs*FmnukD&i8{MC9D zPKG!jm+~HpWmVkA(%T_o?oV`xY0LK;^dc}S;%RTkj)EH3*Q1=*;_Zk{)y5G6ZtNse zOy8T8qw;o4t3S5L)nAM2=Bl-tgk@$u?OF*0tYSWoeD=HFYd*ethr9v5xe)vv915>F9G^e z%_l0!t0%gV#}N{KjQvWqKv{!F5k}~yR^dSn8W5yda z5pS32o1&m!PFmUy2jgIVw?ih9oMVGC^je7p zc~)K7xoqLBB|C&h0mnrLc0yBBLZyarSKn56fu+%PimM~|toK?i3wOD_0chP=z zmw3VILr_sX4aVoF}4Fe|9osh72gR-52E3XYo*tLq(A6c&2tf);8;|}jmJQ>z`M_8`lV7k;yH>gf8a1D?)$%yqE!W%(&%+x+-@y@$bkkE^_ggB1MF-sFvCt## zpeJ-*%3EjJM^TMqZN(nsD;iZ{No{z0SgCML;vwB=b1i<&pn4a=ZD#U9(i##`o)dI1 zvG^v_NS#gujW5!~2!+{O_kyu=*niuQ!b#biNtf=A5<}Wwc?2;|eb#p;a&Rmx`spCt z?2sBJ%|XEn+A*c0J;iZg9V#QLBAB?N)H}-d29B8x4=RklWKY3S;2V;uz7a(vlKESR zj7kA;3@a$4tAq9)`BjHUU*m+q5WPX}Gtugdl3E5F4r|`$mRN~)lGW&>lgZGN2USwY zFLV?Y4LL-K zuN1I-*PjJ2^Hm?IxV^$6N7_vPbAXZFRGYU!1d|VP$>^29o!{piBZ&r62N`R{E+{r> z6~vLodh4^)k|PW^A*n zl?|Wv$&X}zyP!KX%NR0{{*lLM=fB0y4$_i(EM{|PS%BlgI`(9FvuhNU+-LdqaCug) zE~?h_RQ~ z6>v8d=qXRq69_R!dW(5sWauHqIMa+4y-cSoDl4T9yBJiOQ{V}O#TcKnx2~226QW^; z-o3~RV!V=nY-D%Qdj_XCrMrTn=j3`ZBl`7MWW35DRiT-YCEtDUZ@F#Kyp18De{^_e z?gWNtVXY}&22?e1#9Ll5(bEL;?tAw;SUv_(vO6{p&*;5_^@~X)_VPlyffEPSHR)m2 zzD7Z7B7U9Z9Wtw)SGIpnUu8_!?MaLbtLSoM+zZkP`I}tftL1yhs;O{UO2(Y?WmHA> zxN>dbbNsv>=W4EfGat!Z`HFEMx1r zqz?kdz4!yKUIPjYdb!H%I{}cTsuQ@kklsM(?1FM@)I+c8fRX$PZU;rcFG2}$R-1;Z z`!|<~&ej+DZAB#$KJ0r+f#x5_P41OTe#w@h*;B2`!^M*V!Jfw>b~P4H-#Qeln$?Ik zMvlYO@#e07n^HFhZ#YRca`(@H#CA1@S+u*cBH@65;Fx)*yX2Q}Mf%vPL>*VI*EV^7 zJy!Kk%Nd*j%a&;cRSeIw;z5HF3iK zehQ#M{x#7R-dP#E;p#V?l-GxSO`>Iac8f2=%uZPx2gx*x*Dd?yGmUrrliM|bVZ+;L zMn^A=NK48X zKkTiSQp)^6SCRXDeK%cOvJt?_7r;D~BmrJ<3m zZLpIW4kl08c8Sm*a$LP{48)gPNu(xr`xNYl*-b=YdFp-MRA}RW+;S2RwGh`8i5Cf> zo0s{~YN=q!ERKp`O7j@>=H)0jF`k`?JiuSZr_hpAiwu0X*|e8A_Rqkc>CX~9>)#Vt zaxL?a_$OS1wLnILH~Zn!;hG(5$TRg#gP*cLTJ=r)xH!YPmO0&uB(tBBR`%5*Z+eSr zGUKDMAGdOo7zuY7cO0fAaT}Sp^RePYUMv{ISYOeO1lM_yqA(9)YNME125>Np%L{YH zf<}6rt&o}pxMsji!>+s^Uwt^_l<{VvIXFx+aN}kDVm2oPnV=YRU6YRn-)MRgG=RJ= z4jSanmQy+$(0!XnkEb*7#UcH3XFQhR=GEL<9Xsjn=T6s?oLQc}{E|9by_(qE$iee0 z8GZyv8#K}*UVb2Y*ijtQ=^S`Xr7N9)a4tIvLRq>4zH>cN%!keN8Bd!k?+js#-o0xa z3pV>cQQ8)i2_jY&oR-$nqKJAT%;|bYjgG-ebJckP#Ue>BPi9@8M*NZA_vxf$Ul_1 zj++_DSYr%nvRZ$RDXYv`<*NG+`}~d^42DG`MMo50@&rV7``zq>N$3EhpPC+0(n{U% zGycW_&bU9xfE7o0Ow?nrHL^k0rBEhJW~^_Ft+lG^G8f=cHNYH|Gke_u7OpgsLT`NR z$x^mz`gf8MVyAMvE5OA{IjPz|y7gPbC0+nPOSyr*dmS&isY6vE(VWe={E=vMuvF~T zAYAT$%qG7x+o%K4TW>TF9uFabi#sk&@ujwdrU_dzOap=31Q*~~Nw5Gs%v6gGj5yK; zSMX)|fV?`SzjrtpJviyOmpRgOMf|nRsGJXJ z#bWqbKNrrNBPqYevB=Rm>X8IgdL^|Q-Fv@@R)fKA!5?O;noKU%NY&6?>-!w|l?%0J zpBHr87cnNyq$jl=e1la=Je2Y@a}Q1Z!pj|rwN1L+{EyH$e!kFt(yv215uM=l4AtGi z0Lt*1)=5G%%096IbpXEJpxEnCFB1cbu{-U+DKBq0K65^s zXwC+uq2a;6UVH?a$@yyc^>&5C0dE>zaYIMfdE36@+A_4Z71Heuf{MH$?{i4Mf_aUo zb4e-zX^&PXL>Z0DxSCw-KjJ2fHz+e3S57-Qg9%R?u3`ofQ5k~67J(ABD)geqbJ=S$ zSolbSxN*qc>gL%Rc9uVo&sPb}OG*j{;D1ZxEs(y>6kmET(}c-N+tAt-?V*0B4vSYw zBdG)4fh8XFas};x=tL7y3`l*s{!;)B++c_n{OnqypRxtxWhvorO*^W6WkU+hG(9e; zR^K|s9)P5t|2`us4VIq8|?$Pua{fvtCE#@|q9SxVVbR z_rRyw8e+|AW*r}f42_-&$q{y#=u#7X<*7q{loXGnoqwGijv687Ae0`?1MO)#B{6v}s#T02JxmB$8YH z?sSou{05vej4Zoh4L)lTl5yti+fLZ>VK*_=cDZtIqcs!5M*4pNl(iY$s8{X&sO2iuqxH*2v!Udpz zIAec3#-Y(DJVrzm-IqW9q;xLFpY1eJ#3xZI^C?@5S&@7PO5jhyxjUvF1e;X)O#PAH zrP+BbR)T)Od2O4&*%3s7=-N(3lBSTu&JWSMEwqf|Q*2cN3@Z-lo!8_;nnH?k-#c5KoV|*& zL99jq;8bUbp=n3ZVhU^(>{YnX>M-Ta*%+OFl8;CA)gINpU@8 zgx}_B8t0csBF}FYE{rIzfb4$TNRHhlUgJHA0m|OH#0y6Eioj3&?wJYeFqoTayl9OY z+aQ?KmqDEUa!uZ01ec|jvOYYx^cLR_d6xjm^r&Q9ytjs--0@8p@Ov-piFdmR4QJtN z4UZPHu?mmO!C>68HTgU9kSK9gI{ML-4%d8%8zmZ&fpUkTo_V_Os5MSH!UOiY+0QEWrAXY-riR^6?3)^B z`^GzTS(PBhe*~|VO#ntmWI6puC9vq{vj2`KdfGf_77KB{v|cZ3nU8FdAsiK3gxm`5 zDQc{qG}tFrhHv3Wb(KqE6dG7@s51DeNsz<)jr}AtK{WWlVu!HysT)FJqf3oRZ#=FVt- zq*3=BJ^=i%EHk1Y!ftQyG^ExLR@KEhTrWDBcf;I-i<((1yPOQ=zsE+tSAC##`2p48 zy`>yNT1wiS4bd=lPn=Z$q;>v+Y@rL3^l8x%>e@K7d1HUravCDD<-YPm+DsC$TW5UG z$|fUzO>k+-M|om3*b(j8`C+JQVf$il`GiG%($KmAUcqopP2VpLMtm-1#> zKk_2G4Q%W*r(=kDkpGK|7bW&Y&AI3MUgDlP9Dr^|4=M-Vfd5o(aw zI((>mmKb%gCn>=T%4)oHHK$cb)Uw6QN5v`Xfe)Spi;Kp6L<*WL_op2#TS^IL*(#TV zKG44bhJT^SZ3$`{s1bB~hB_}6Lg1GR>Mjq|q$;-%NHb0Fc&6_%4VUzMK_VU;NS^x+( zKZl)|ya*T!Pm8QL>=}ND|2|WG4jz;-mJ<9x$oLkaye(PIZwOb)N4TV>qudMw&vZD% z7a)>-4XQMe_lBNP&PptpZB{`!T5YOoP&ay9YbYyl0SX|Ck7k?KA(QPpHO8*w9f|gi z^1Uo`myyA%cx(ELvw&27Xu+_Y+%RGf(}Lp^lF+h9S&dxl<-_f^qPk7Zpd@V?>8?{?G)&hK=zo^Qs*g}hIntNsY6<^Cm*xfEO|l}@YD(XX zQu(gUtC%p&(k_sD7g_F)i{iYw5>g|wPZ(?>03VOO#P%sc{8A} zuk<$BwnLWc-j7=biM6Wbr=_oZbON)o&#(Y^3thU;_=(mjtijK;PrtzqR|LD4yYi1n$WC+rC#1oq`Xpo0zt62MY@qZ;J9YRx-Q`yz z7)3Q4`4h+g&Vs?DMnN*8$4wqGlk}9gwX^dYDg^pZ zaR69PW29;OjMQtfDXQ^lU&13=cyPO-vpQIqDeZQHhO+vh#DZQHhO+qP}n zw)^X3{$w)K7k$02S9Vs_s(O@?agg5!p#S8?tjV7urZ)V1t<~ah%-!~aejcgQHZ}b` zr!xY)VX6bH50<@!9#Q+XFRZ~Szc0=`LhFT~@-Q*uV_AXIY(@_Saw8h7O8FVq3?mjS zZ|OPv-F7tn%Z{p#)JE|w>`gta>k)ofNu3D{k4fm5O+;zi$}PU7u&8H{MYqVhV8s-&PORj3@vdvg9>lEM9qBhb=&k@P>4_B z+8@NA#6Yzs@xqkxja&PK1a=njBXkMnG-)C#o=`Hya7Y_vw#mvYQiAOWAavSIVoIaz zsPQyj<1i?p%Os?XaB{k~K95)Xd~)AlE*oGQBld}VVfLaP;dW^dQQ?ycwe{~j)AnIu z2`sqr_xoWSP{E;6y_a0CjX&5 ze2@ix#%N!l6#A3wF-Y#EK^FabPtidNo0;tQ@|zSaZ78i5e`(WOtPf1|KiOKbLmMhf zr6AhFV7)?J>bGUCRPDuAVGy9kD=owP?JRgG{yCT8fEex?$)Lqdis3-*ee?Nl-!l?2 z(Z|ob`7$goXY-rwlI=ziBcv{bqZbP8g`%O8oC8+FkK?`&0<0Ty|I;!}VZ)X}9$oQm z-_-qrM}HsC+P2r+FgB;mNS#w?3_XBkP^|}C7vVp#jb0%d+5Oo(w|_EHf#V^nTyFCU>CWI-6J#eaXan=y|32HJu{L0rw5NPMVJX~;4 zP2rT>A>@1{ptxnMB_0SJ_wQDW4FKPwI)k(Nq>W1_BM zFI=VkUYv1n)wZfqWrY1rjXMJR+mvX-AU|+mLQXI%5YL(U;yopA)#z7easZ1yTS3-| z@iJHbEnkiX&S>mgAzGm71*j`#0N_FgjQlsoSh*NIzyB)YZ{{C=Y_*Q+=sR<$)T}vwkcx zledDki|RKt%(S5GKy_Xp9$1_>;CuQvD6nrH=$`bdQWTL>@0P|#e1vI}Cb${5Ne3^T z%$PO5ga{qD{5s${QA2IRRU^xVfJBYS;HehkQ-`Fri1a5p}D-d8o)S^h7cfoWNgzP%WYUvNHHDPSgtm z{|(YRp>Rt8O^PXNHg_3Bw1_m&FeXN_Z$+$Gv9R_7BX>h3OBe)Ig==C|QE1A2!Zi&^@pis=+Uupw7@G+{mhc9NNGE(C#f! zcnr0^O4>p5&SQVo8D@!jTwU#jbC$)s!v*75d~0p6F+uzM}pU?d_EbJVoBa zB1E?hhYn2pnBvL(P%d8c%c)OynupV~k15MI3DO4>L| zImKnQ7&!N}_8KN(>|D_CyhhEjuE%Yd6S#ZYQBO?bG?!$5Wx<@qP`pJg^Qj+|C8l06 z6Y0+r2%dP8_;0gd61Z=}3+nMR?WVsj($w)%EDt!T42>svP04o)Z4pCY6|vP2U^l@t zs#k%`%Z=p}&)~&1)F_z=>XkrP7l!4M*;5G}iDc^2dxw>3zm+6IvO%+2h%vlOSsI^9 z9TKYH0(q(AxE3QgPAo2h$LD97jY^J=mD0eVwtqsjj40xtc+ z@HS#YLZVjWR(>uweRkpgk`dvp84AzB5-hZG$36!hDcaSsAs@Jw{ds4l6Z!DMKF)+q zUP%x|K~-ju4{k?kN$oqry1nt4TgPm^CL7^mk*n)IH3mkWTs+zPyLlEdy;VK0`vK$T zHz(rIJI&`|kYKyqUntmwlGOfqy{31rmBa*R_|mUR?L{;&Q%vQQ>Rwx*tz1bA zA?+w3Ifq(kLcHv_dyTHz+h5&s?pAW~b&k@El_n`l8KAAlxxRJuVyw|9U1{8PED zdAOmNeLH~~)Wh!;o?Y%{urC>J7|=a|>i<2Uciep zH5qKfFu0$va7NY!W2C0%v6gF}*Ho zY0!dfh)qgKKe@gSeWn5KKy+@2Q(1mmg>kLU@@WQcrpG@TO83Y_-+ZZov*++v075gX zF-LY*Y`(}sUmpZJr-KPX1g!EW)7Q){QdJeb7B+8R@kM!)ID`7JIR320)`T$y5_nO= zyYyXn?2Bc)UTA>UJrcjG6-1ZyYXjYAbBC(&6YwDb2FBl(C!;!Va#>A=78iEA zASyrjZDTR0Avc&IJIU+zizXT}snl+=_U3(V|}?#?W(1N9%Bo|5gKUQ68_ zPm2G^CpA`3_Kysr=$l#?K_R57&nG7%gDXT%RRH}*EtkoGu>pXp6=O>s1;CUxQsy>O zrt;6|LGC~0NB3{&$%#1Ww)uYpwZQ%ZY8B)_{%@d`D>u5? ze?YC$QMuN?%~-Vk$G-8=d%uK*zrsJ&9G+j~g&_t;KpC1C9RRV?(^OXmn7>8Y#o1}R z`zwA6Wc9GW)L+8mZ+L!y6MifuKpB~tU%{@;^>NJ2OdyJo8ynnzIx;x`jjv>-a;^ZR zUfRN4e}ynMv^G3{ehz=&gcpYIad3gIr+*YRW%$S-(YN{PdQFc4kK(eqz5(qkZ5^5)_t{6_iWga{zz;)#zewWoc|? z04MAGE-cPZ9Q#H1rJ=&m{vGB1C4SUp0sLo((OI1z8eag;n->42@nZbB{9<4H>Ltg= z_k^+IB7>9r$A)A;_76|KLibM$-hTbfv%0!CGPO8;wC(?0Kkj|?#TZ*&8d$4KK^=HGfZ-)Q5*x{0N6S$+_ zhQes?6_zv2A29rT+WpP~Rr47eubuN);FX@#ivE0u_@dxRY$7@Q#ilITPP7hnHqy+o zvWR_&-zGd=ovpiTdXrQJg_?+^cto@sumZi1+LEHALn@Ax#(#+T)bGMd{8-&|=kMeV zw^YA=Adj5sG~+f8!`jNr^+qxmRnD$vXeYW#3)WlFg+;benmt7%dFYBMh2;#W9=kMu ziRzoB2_zWAFSrl%(q|c7XGwd+g4M~jExT}CZ0p&;EAQ<4N7~QT5*JIqas}J=GK-4x zI2E|Fj%bpeQQ&$AcRm?d70H$q0hsug|dK$vcZz7Z_!neDc(ddLPSF!E6=Iug5Ox+yi@-Rm^xG zTl5qH-|)V`A5ra`_u3y0m)Lr5%SW6IU?eH|Yq+{uk{014%@xA(YEQ{)g>YhSyPbYl z@k6uk&t@+j=VcssYd(8Cih&P#m!USlL&WPb@u5f@SiXoU3XS4WQ= z*0`54r(2J@HKI&CfG|Nstm~gb&0qzSMyTi_*TfqPJ_}7&kA)+Q%tBlezcTE;yrw$zF)n&qGw_ z`S9u;&|Zc$n@UeKK&h+ywq)rJx48fJ&GW81A?c$)5Ixz+B&SVV>CvHBuw=6!`xtTU zI|tc~;WW53r-P`?gS!-8s!YSKS%uo|MY+PsHMorGTJN*PKNS64v+jCdt{OW7smO% zKB{6f0_BGP$8i}7Dn0i&kv@0c9D_y{^R<_hDf51?qK?oi(7m3_!8{L{yx~A>>lDy~ zI?ey8DRF#W;sjL_8+x}+JsO{~Yw3*`i`ghJ*{8|$sSxu18=|J% z5P2A=bI=`G332`RL{;dRlQV?8`5y5u7af#*yFa?_FaV{vtItgY4u%n#r*9Y$AD z!DptsZjX%EabE7uqLCJraiZ8PNNZ34dd$BkB^$+-X2WGS|Ym@fkjSMvj z>21Nl=!_#%wsh&PQe)#$MEpK$=QImmMo6+N)h~3A`U@yT>USp5OY<;v1d zhmz9+<6$;1itP}%7Y73bK4JCX@vORgU`QaxlrNZ%0 z{Z8|6(>uGQP_n|EBy7^SL@}5d_(srdU$ykC!RjoPr9O)nmHk3OGc0$xz^WkVr!pJQ zLbHPl?1h&ON{j~RX$IjvyN46F!*D~>WCVU8D8Ue3$1Z=QCzcMPDc_d}aIBY< zj~Eh$KXM^*}c7OS8+VOWfz#RD&XI}5);m}*<4vu^tUGKEz@mUmcRI5 z^C$5$bV>+!AGntc;kq+PhXv0-?2dD!({LUPT#+%1>XC7EiZ58H&=6{DX`#Xp6F$Sg zlE61=%Ph2^Nt0fY*ZWRLUckKtJ)o|~G~-%9Y~be51fTMAad^mb>`(1R7?&E75eJ|e ztCseABnKkr3*#J9iH~qYyhl|TYu}rVdo?uGa0SSo&pQf> ztlMovR1BFXMI*dM4SxUBiwI?*9rq|jX7gJB&Loccp6dB9G^Hkwb}1NaCd(qzidz(piC<5 z)}XD)`FoKDhHd=$o!2RNApFK{QLJ;MZGLwFRl*kipd>NLmfs7?Qh75}2?(BlMZjoD z{Sc7u8?#|=$HUF0CpF55P(w?K#C_d<8!qHBIPDZ41}*EJ<$m?$5-{ubV9D4T2p*5m z`G8=B3gNIliu=C&NHT8;WGK~(Yd`tgRtkv_kW4IfqZGl#8xR2?a$BgDrQFQ1($roszWJ}6sixZ>W*A5hpw_9PL9lBZjo$$U+=ii(7A3J7^^jgwRzOddZ zNaJ&bhX&F&Eu{hTV3JZdh*`?12c@dn&`5xnP-Y#hdsf!ze{X2uc5nAC z@Uyw^&1#eH*@$Ij%AGzzq+Q@kBknfPoB+;hGe>;ulAe9NjgTJeH3qSg#_rP6J2VB#88 zXv#!X=8`8CKiwo+X5ZH%e}TNJ!CGX!#Z|+q20`y7%nFCwe*A?K5%!5@Np9CyhU8|t z+Y%_ixS@^#M}?|qUr}?IRFtzd&!}ZA2*!3UH;e*cS3yk=g1XaM!+3T|E`@fn_iaE^X1`vzKH@u~(8+d{(MnzXs~z zL-)o@Q|^apzk7M9G98>mUvC<0k|i9by3pl3wfON`BD-@IlWEO8jGy>KsmFC|DoWXPTX)$G;sw;{VBl{^t{QIo0^uE7#Rya(wI&2s zlsaV*HHC}&t9KKZ^#!^yb~rZ|eqTOpNAzl2=qy$GD)hE+@h*2GW2cIHIF98pHs5qG zmmZH6aWc!Mo^>JekeNenRP$KVGMZ&GO1(xtc8NL57KAJ-s^UMy&pqW|p3|~Cs=3J`|$_oNZCPZ-}03iwZnc zv9H_ar?Asz8ya#8bSCuLNze?K*!{Z!0p(5vbf!Dt*ifKY_TFBCAe1w;SM&~;^@X0% zl?>nCD8z$+bfm0ix)(#%Uhf=bf{K82B~p5)n^K*_8yE1hqL}ixC9n=+kcbR}WCW#9 zwm2ohZQGBH4Wq}|t?ymzT+p$Wqyf_KUrpC|KIO`=4sUYjFYbDUTccipoX@xQKztsg zS*b~tG)_$-?nZ7fNUz{W0Vyn|r_?Buf_3ue@j2Q`(3-$jmc^omB~%xu-ZUBsgE5fj za#f%=JXI<%Z@ep%Bs4P%3rEhXDs}RIH)-vA0?*mIw;E#0vg&F9bY)8QQu9v{jdPgl z%}PaefI94mFY0|pak$Vv8TIiFA4eJg?py1>wXaofLtBk>`@{x2CR()+kDP>*(1qHu zgHEs@C)Ub`6H{NTA_O%{!`|5{kKcCE}9d6=fr#ZH_c5+I}XdS_O`sD?et z#qU8=#?BVDJz$D0Lu>H2I4OrVH2LTc^0r2dg` zL-5`e%%B@EP#JVx;SmI*no$!bTl&41I`=xT;#T826D*^{zGCFVOihW7(o0EEb4a`? zaBx;MNI~Iu##H<(CR-G0X74!3$N9H3Tnk0se~Q=QL-??G!^?6XoZ#cdPx&)E6Jr?^ zrW1pwJY$ZCPuQ{V1~a`^+!EV!@b25ABx>e6$FOw@8N>!p=GwZACikmSEEibh=)Tfi=MLn#=`>sA};n77_@SW&N)R)iUTzgsB883E%>t z4!ZD>6o`)I4EwmZC)S`Y+`nyq#K5gVnUiddUY6>#&0uH456AN^tE=-4_+P{4F7YA; zz~k`r`GK09X{~NYA|AIGZO2@N#!^Gc!PLVj7d^hK4A?{Rf*7_jx8pOe&Vo}zH2H@@ zd^(#p|F(4co?=na%574saR%FqqP^kUnY`u190X1`3v&`(nsY&4bNXF!ZJ96naSkpn z-!%`AG#QPXUeMI?w#9N+V>r_mXua|epL7*unD2&(hH+T~I!yBW4uT`Khd>mv9!iy` zK7Ked?%qFvb%zIBZ3B@OQto<&>F@=(vBr`O7IZ6$U}B63l6Uku+k+sLZI-RV~J;CZmjJgSanTH zOZXr@SR$0w4*2FD072>uW0Kb;dHm~_vy7(BH9;hJ@_d10m~DG61X3nd3$waM?nnFY zMyBEBFK>LRkP_~FG~3+?_2)*D`!>sEg$iIRd9GAKezW7u8GASx@GNbk!i>n*wZhEs zm3nnrc5i~2rhDB6NmI!6qG6-EBzP2$8qOlEaXnmNJ`s}SG*6`Rx~o3349}|i4jBsC zu+VrnaacKTRYV@IfxYLs=9kT&8}aVvQ6Ly)Vh;%8n)ST=@gekM9win z(VG3N;+=XSu$6)r6hI18muD_zXHucLU7AD%sa|%eOG3P^ivHwm^QD?EX`?S8H8q=N zLRUFSn1uWN47q0H1J!HZwD6SJ`_b+D3Q^%CC!EP^)rOo}q{_7)u9VuwZmS$RV&Ecu z2p@_PvQldqjAC~#OvcBRDNdwuR;F%61>+N1LiY__4P84o z(#1_=weBoZ1SAqNw@~N*Zj;J@!k|Z4gQ&TpP5o|kjV6i}^c@C%A7^3LLE3So%6z1! zY$HIN>IoLSl}eAZsr{9KMmo=x23k0XR!JhI(NP06>daVT-7an3G5w1?d~`IPx!Pg+ zTvU6UwZ~V^wW&QVQN=C7hv!HQYgQOXXM!HD5Ykvz;x=B$%~z^F&;|pf)(KQ$fuh3X zc-Kmxnr6Y##a}D52h3S7ML|pke+mvl#yGTnB0TWE6voE+{+`9*#+W?db zbQe}J*BJGRAVpF;r;u96MJf^+6^B9xg2^rDD@$sN5CLgc{GnVuA7ef)z@B`PUKX(d zQQaF8k^V&c-RCWJB(rJyYm$2l`rnzq$I2w&KXUZCnhjZzZ**iIzFo0}68xUVMM1B` zZ@Dnkgr%=K_q^E_(L(CBZV zd(`cba=GzQ7ksF9-e`lb{F-%z__D=pUe!u|5)IQy(*&-CHg*PRk=(5fwzzQ1w% zS<__F!PsIM#UhTL+OCb@52&!cNKQsj_b|u8^n%3ixFmbPcu-_03MqJf^3q*zmkY>E zpgprhR(2qGLeVLf22|((t1YLXXGY=Oy9HpNqndK(VS=;Gj2uJK850i#yOth>$4NZw zPNRq-jFpZY<(KNq^Td>ur2T|ZW1M(5HIy}2LnZeaJ3)nNZ$|{=h=bz*y%R4iAx@uC znl3Coe!zuS)*36_tnCWk(=XC~x?RG!K|c+b5U~Wm2v45X2Q~yv2^e<)w@vHJU$0fI z1u9shJ&gh^F^J{*^4db6;3z(q7D=nsWb^Pg@c|s>aoI?8F{WwM44t&T?0HM-8>EN2 z^ts@fqGN65D8m~AM?4=ty2xbrucku)E0+^4J}b>6Du_LPrQyfk)dCdR1>Mtt{}sBg zvKj(Mdk0wfEp4w{v6%X|v>^%^gat=LdGyZUgQ3|@NTFlq>@t?B?s^edhibrTFQAY} z*b{J9h*vRCf9{}19rOt{#&EUXtkh_Qs(|C|dpyCRXT04i|HssR6M$|rDE7r=c)CqU z=;IA?yN4Xk6>aOn3fNu%ua0!FRL&P(oaNehJ`Hl41T$aHfi zVU$hQH`fyc?$Q6?<3q58pBloefU&O07lzvZ!P0^hqW=W)eM-iaKfey>Ea8F^r&S58 zWQX(Z1$?O#T16f?``TJHoYJLGDsjzK*c8gfLu0i&5Fo#Sngg^D^Kl+y2lT|k3zX-I zL(3Jl9Fw`P=Io0nuM=TCnA(3vdnSqMiZ#?(!<81xAv@WEob`!BzDYVUe0Z?1cnVk- z5!fV#?A7T-$ai)5o0uEnZ*aO^;WE?4Lv$tkFfcRq^58cyN>n0dL-LRH5ck7c~K+E)1wrTLo7HIjlmcME#P4$x zb=JJNnxL2zD45Nc6v~6!S?Fqm89?h_FgqI_`ckd+H>IOJI!?wAJsVUb*BF&7ma?|U zm}8LB)-E}j^9?AiP`QC)He<0W@sfEVxE|%HKV?I8a&vmC zD_()*V|WlF=sQZ<3nbbWi$#dzEP5t z!{+n!!5Ru@dhE!GH0xXE5e6h$at-q}X^`!sb$;MF$V)`!DEyGvdJrPxMqRi*+}7(ysTzYqcxv zWTaO@tm=aSIj7>mm=~GDMJxrVP~M!hg(lHWHE?Hf+emN~G9K|$h;7NKef6?gT&|~6 z7SR6*vyv%@VrDI(aAa{Op}(&(ju$~FTUqDwn8HmIL8a9?cH7fgeE?hS?yaCcoQ8SD zkraXz1Uv3v1~>D(a=8G#l)yV-Hr%?#!?>mJRDMygO_Etf3jFiGHFpGw->gzRBL+nb-KPAO>iY+B4&HZhWQ--{>K7r!aRo#`yNFxV^Fy>Ut#sYIpPiYb>xAWK>|W8`Dj;K0p}q!Y+s{66K~B|vd2c5L*Y(`z5XfJa&$!s8otNMwo+Fh~6}nG8sv4+|7Zt&(NbXV3T6+ ztH21d##GbZ9r`?zRl(x<7?<0ulME^B@tOE~G+DX93|;Uy`>5bwnqHnK0}!xS;~^ zL}CTvoXy~7H3q{N|K7k&{T_WRZmdJvLpjPccPhK0m&2e_qsc{2=|p`}&IgZXa2vgJ z2T@@f3ZlD;G*4;#aTx7=($pEqraSF^zS6-YSWcuLsZEL#wPNPhMOVJv-{O{8w+MQA z+9Y8ux_Gby=ci*!I+0a^I_@2&G(X()^o`?SYWW&_!B{FH*2usf{j6+D)c(j?sHkp@@LTH#2WcUV-!u1j z%g+dS!zPc0!2WO6?S$S)QrSw*%CQm(*}_#=?7)J0RyQ$>0FU`Xe~6wcOnAZFj{9BOV_?wxiXBD?|pq{ zCboyf^sp%$UjgbDK?;NK^M&PyO_T%1j3C!UaLpssu>6LqI+d`F$dyTv;WSr|ctrde ztr7zuJ)&hGacmlhzZz+o_`;n|H+RIhD#;C=4kS1w0_nE<}=N>T2C^ZeHOgY+I#NW2_U5g z$Q0fi_?7V-?=XDaa7JXDTzUEsB1(kYQ_7N-?3yq+fw; zoUY>5M|T@Z0+2PiD=`}M=`+kB20!GjpCR?7MAjEz(Awstv#t+nE`}<6YQI0nXl@39 zOxH`m*HCh+%y)X5vk^T^P17yH&M6#7v@jzB=0WL~_>%s@R5*jgZL_VPP!t{cZTv>J znJ0!NK8A74YRl84l|rAzt0>uGpiSb%`1;0b>vouGzR7(~zN^$spMnioZ(Z%nvsWB! z#1l!ruz($Qiw6jNxkE+o>EJ5kC84lT?TSPAf>T}j8!7T0-WItj{gENo=xTRGB2VjU zL`?82&no1bI~;%&)i8lgga{)yF(d-nLqIrFKxeV^+pgYQusK6Wd{;D1Q6bV`LWp)y3)7A#qQHINQ-Zj{myGt3R8+My8D z!(c60=Y0{5qe3F;yw}3*iP!*iP5+#f7TN_F(BFP7^NK8h-g}{}jH*l8G%M59Q9|^$ z?u4@f?<59}=8a2~t{qiCLW^1=>k%Yyz2mO%*gVwEwZa1dI7aH6<4g8SKj`?$Obh)P zepwIjupQ6h1(%o!qfpYIur)*|mor51F@4T6jwO?>-<(Vxljv<2mCN=b;BFO*C2UAh zTy3W=OT@eu>!x)msOW&z$MLh%8}_Gr9_wc2ehF%&>LX9cNys*ZVr>>UlJ`-QrNThlSQZ%)>OCPuUw0k%Wk zanshL{5uN%Oq=^y8dl|oSX>2E?>D??U?7c*UVFXq%aH$}QNl2~%P^lVJ?(4*qzIJDH=z`!uk(;rYmae7Qj(3dm1BrfURe7<7U_Y?`i%YGJ8T2e)+;u_b35aR?^lI{(Rb!nLAgXUeIU5Y9t^+Js zFr0|ahkd%ZG^kY*No3nW)t3L30tcSb4FWO8h?FH&|NT2|+g_%tr0nB9EHYYLPT(cp zhZ$<G&9a4vh>Uk1&KW!z~B40`Ci%G~lWEVFw2^$SMk5N8o;g5E8% z;1u1Erc4(>l_J&##^vvXC#8vvFdys*wh#^_!(i%RB?gpH@|Ha^lpAWA`49XW{H7iD z*i|igz!fS@x)DWz?)cUV##_t|TDIE9r$!KO6e~1g`OH*CPA2f@kPIHWLSKqj_QVvR zrJ(Wq_mZcebB+lC|E&ku`KMoER1}^B*L=(ef6JYeDoQUldsPfZ?$L5J!7DT`LmiuS$EsUZY*Ty?$C;BVP)2Dn{!mY>l1Le7FW$#)$ zD(@*Jd~JMzY_3A+3kDVbrw;M`{uazg z4Rymh!3d|zBmNS{Al%&gC)fV`bmd`%-MaD>p{`|9jqVnySkfH~A!0RR0qkU7$OoCCg-q&#WAS&Hco3jWbO4RTCzX_&6XJUf{8yQjo^=N zrQgZem>kb}fZWFTD<>bOA!{L8DxtcbyjJloBOO_gBE$vpU&`Iya3NP|(56 z6I$!Wuds4>LYs)~tr49PL8KP&CcUbM*ANr(y3yLeafz z2ZO<13{{J}xH%@chk~wt>NIPbG(*JS2T&dp621|yzdeQHnjgp3@&HCIo{F@pm?32} zK~%sZjqqQ9NkDWMrlFU<+0rbvD3}Z)8G9R!c=3DrXn(3DU#x4>HHLA;?Ariy=O+LT z-eEts>J}DPdJOaqYnNiP*jwQI_)IXxkRsh)OmK{g6WQa3k6?1NbU?VW7|Cc&(bYAr zNxL9eQ+R04fLH7=P@p~{3ZEc(>JN{M{sQhRCPeDoKmV;f_zR+g;GSbNO^qY%kzQ4x zTap}1f#-BJMxYv8y4VV?F}cNzE(zD2-NrdreK@O@OIMm7+wWClR<16m{6e0yfZu$) zo3|?>*ZC5%v|4Ns6Q-H8x&xp0&y;K-uBKR@u}{zHM`(11ar4C_7oU<4fAH)vJS@c2oNboPKCaAWw>UoX{YJIpY14VsC-QKweHxqS#t-5>^f-@SyA&_;c?gI}b~y4Qp*vbDa4N(mBWRbvQY0R=jM0 zi=KraP_!xyYfnUw*W;L0DbJ8_$M9H;Pou1`%_-|*Q#^QtVAWz@=5WlfQg3`RCf?Li z`DS67lT`bY*iUx>zQd!*xg0AjRSU&MaJ!{Ggi9wK!}q2W5c`Z1WsVN z5!SmNG=85miLQJ5L}WZmE%HM83@*UES5F*fJV&UV1zch7sx0>3#y1>f`krQMg^vs$ zRu1)_q;qdd*iQ&!mRe&z#N_s&SzpEo8l1wuVIby8hObFQpnSU?t3g&zCP&{ZEM?_^WrvkJ*fVMGYyxt2~@E>@BNyU9KK-$HTQxWreRWH8HUSDNJ< z*N2L>~?aT!;1JC21>2Vkve1S_n*KfVk173SLCOEr615 z1+%npnuMXwLUGG}jm?2yc|8IKqC=ZlJ(=2v@J0>Q!y3%BN{z3DVs|g1stIzSyR;ST zQ5S|LGRn@h_v)#FF0=>Tu`EITQc0&ppH}Vj&;8)d2q-*Sd!(W;8;Iv70P28JEPb*$ z^wO5-U7Y$IP1Kqzl|FzbxsonZMj^{Zay|Mp7n;d2XvKr*mUltZeo|03U>m38jzjZ! z!g&GP zt?Z4;$$z4s(iO`f_#k(@wwFc@mHT*SEf{W{I6(79BDd;g4a}qjm2+^KT+WQTuQxBZ zIg>O?-2whHl&y*YX5LI-%B4$}n>qy5dcO)@+vH&7hlePg#)YrVi@Ez}s;Scn*_QE` z#@PtDtYQo_@of+BM#a-J#~d1waREg(#uojs*22*Y6X1v>|C7)A@VddG#4xsPjvzb% zph?rMMfqaL?b5PQl5JAu=3IB`2gWT7{?~p+MUyq;k-?p;aJw&k!Z8V`#>R(_EwNUl zcTG5TPOd&oE1DdAowrzx!T@^IuExa{SGrNp))f>XddC0}=b<$;@X#Et_)u=RJ0o@_ zt_byHI!S#NRXXD>A;F~CAGKa=w70>bYJLf(>9>sXT70m}qNahB%(Bw!yMw*$1tQXG zzk^3ncu&*-en+gV&M#GP**!ztO~{qB%OSCu4Fs!8NU zij>NtxA9j<2A<(p&GEO@qJ=we#DI=;niz8@C4EL*N3{v_!$tYduF19(qdNcz))GZw zIg|vGaWu!}ZX8&99)`4soBRQlS(TaRIf{$kKAons zSeA(`px5Vek-jmVQI4PKFl)V6C%zLJw|Ge1ThDeh@2Gg|@uV=Hsl$5nG|PJBym^SU zxG<4?R2JVrx=&zprOnRV?^5rXY~?5*ycB-`eEZV{sbVav|2)uOhy?gk^d$?zj;f+ObdsRDkq^O{N z=@1B>!$eBku8X5?IztN76`yW){lu=1fw3pK;)RQf8e}lcfPg}uq75@`kNq&$cK1VQ zt0s+%+MI-_{8-_j7f-Yn9c-XMvoRu>HBnW~^t>f-+mm5sYy!)+tMQ~jWg5zYT%w@=O z?A9QL7tSUddO&F_AnS;={i7@GCF`?IU0p#sHvg)n8ytBaoBBGhsoj@z#F$JGqUnTu zkrjHw0edV2g##lvS8)K39IK88%SG3I*lIH|Oo!5Bew$9Zx%DboA`Rt755$?}3##h& z#4x93ET1T(iqHj}zR>6Vd#W{4CF723%@324p~t~{4RifguNTY8JihlY-B5(aN$|=} z6xD$BsaTX0O=8hk)p4t~qwWd7qQ$g`fUkbpMI$geH&87B$~HlTs6bw?CCjTRD(ja} z@zTHI)yURMlNxLcHg_l8sZ_GNc3>?FNG@a*XPInu0fpb~w9>2jV;9Y1_JNfYYh;~h zw~%7$!*q7iA<9Ne%A1FA;Z615b@OAIgq}#ux_g6?_y4UO$(d8?IlV4R@Yc5%1LJ_zi3K`xz377EGC=D~ar$kqdrqM> zuCeG&q8!T(SCI$cw=ag`++eI8xEy@)SX=lu zQTQQGm+4i-Y@oK4HC+~`_7CW71AlNAQart-ll;H^dCYc8TovWVwzrg!6U1YebmxBg zdjBZ9tIpb9)^eiPZpocu@!Jtbs`XCUx`r-O9Zfk`tEN?AA_-sC4;#0}Gqy5^TN~9& zUC#-ND37*g0p}s_%g-8PWodybM?`{DLtUrTKvVW}F%I?`| z2I49Fs?z27w@eC#wocrP4B@88`p#-I38hv}aSniz=5YX9ntHAZainIPL8O}-`+BD7 zXSeRZbaIbsB>{G)gRL03?J@jW2kP~$$gL5OU879O(Sm%nbUk&wuou%zL z^Y+1}0^3>ZyH6ji(XC#>b1+5F)uipV1Rj(x6a2|g0ggCFLw$!lxYLWSDSM6-;5aer zdO1Cw+p7V9yt{3uj+SxcJs-l(%(3uP2oamr4Kc6BiZDT6cs7>a#2+iiZgw|qf6fFh zV?kJ*&W{5dvvDrEU$-Kfbqr`mB|AG#LV#!r`qSfdSzJd}6^$uLgXtHAMa#ae zNg^#eLGdS2F3NK8*S4M`kEmg0%4lymH{-((?lCNA%5w={++ZC2D)hw5F6xH^^iT); z20{dn^clsT+%u~2d|FL0n(3&65B>xn1W!l|D$*pqlPR^L8R$r_&AD(zv(Gm7IpVlx zKrdmQ@5j+YN#t9FTgVFjBB&7Q8wwCVFliBpwKTHd_lpIJlqd7_8WI`2ZU3>?y>=pm zVLkl~i~6a@V<0Oxd##cby^R50xU+H7jzhb#k#4H%jd_0cjOpD68n+{R%GEc|Pwfk& z5YX#H&tHYo8e63J z4yInZP{a?W)RY+eOH!Z~4$Fba>`&IwIfk_r35Es2xJLOJlsBvD&YrDg=nSbgPRK#lXr>^i?@}28ZSEBCw<#@EvOa-IkX!rAvZ<#{auu=|}4b?T>qanYT|RB`G^l zbeg@lj+L}O$tE6aWh`+YPP`X4>#&(ht8bWl^65HftzbOF_S(5H5&!HZl*=p*r7nI| zJUaPD_+Dv`^jQ7ZhL9bo_7a}w*<1ZeBg-jxLHZA%peGtNSk)bC=}lfT znUJB7O#!YVP*426q`sNfq*7#q;CXPh9iQNQ3i|4^V}7|fgc{XRWG2MhmV&q7)ikP% znB(fd=3`5&pz^pnT;RK(qL>89`KT)5;7~3#j<~s|=cU@{6qet+KZPXTy=b5wg?CPa zP+BD{h+W=as^|hTKlwpSEW{-H>obLdVpKO3yb}t0T7X{c);{h6PXC2PxbRCtPo$s$ z^Wu$M6Ru`ZgF`}jP1M)jnuZpSpGLrF3h3bMJ*%-B*`s2M|L4yJp87=&VUx{M-0>B2Q0Vk6imY*|B4ZW)q!|6w`(1nUqy z5$@eqUP!AY@Hb@J8V-Y$wgrFS9N$Q8Zqo#k3gdA&y02}_w_ z&0EHH*b0og;}roYjUi<47s}}~E5wE)QML>k-ebx0_BK3r^@l!;#(l99qzt+;#AZHs zbFv#{MjYNWW(Q2A$uDNh`p13^1%3L3qMshCjbq4D71AngYdjhv=Q6>{X2rUWxwOgB zfBxO_92EzxTMR@T!oWYfvV)s3ch@+-;y&j5ve_oq9F9Z27zl6{r}*$*KHg;yOMv#!sqbqa`d zbrNLegE-Kf*y=LBW}gwt-m^ctQUMXzUbUK#31K$t(x~-aTrBW?aCyWLf{GAzLJ%fB z7!`ySQ<3?P^F$C$moLEH(|AB&Kc2$acDMSn9^ixbbf?qoXYgVWE6i}X#&;FZl4o(K z!>%lQtc>6~K0eZ|<@6ukOsjnHKV%%-kn1>Q)ON!H%IDmDMR97Gu+!Tw1iPqCU!AEXllg*sVS1V>o66^+#XpRFNM~`ES zc>%m9Gy9^da+kWwgxTtaUP0E6H9$`pqp2Li5*VxZW{F8Q-?`$zyWC5(-ySl@bi>qt zSwid6nc*yJ5s;Gz=3|DK3XD-0toZg+u(uF>u~T)*;27sJtY?2`awe*1d1Ab@av{O! zY0v9_nY8mJ?7}nOI6N~5j=WluTLh*xezZ z;?Ykl{fm42IGSwyqh!QOxa3~x% zR_EUV^`}kNNHnGUSVdg|ODvV}*Ak|9BsU?eQ2BT-yQ{8a$K%@-sEYCPNODtT0*{_a$>L-UFJimB=$z8zsJId~cC`IPVsmrd@*xeA0*d_bZX5fP zmZOI@+JaonCVCA5B- z_eX`Bn_bL1;Tyi{`xoBQfAo{A7tpP3Y#M{C*fw3$R6Br%#@nm`V|)$v-FDYl4Xcjjb2SwFPKjR z|6!sWW7CFXjq8lyW%+y6$ zVj}4V%%geVuM-|~_|Q{1Z>&^6#{!?_po_o>*lyds*VkqfmhCf$!7Sy4pJr9uLho~C zA($N5LY{gI6B22GiKpTENb)SYWQmQgdZAD)O6|PaJw+_3QI-}FsP!}uig=K`;#<^M z9cVH@RDU6*$4kGi+$SYFvGx<%-7)XU&}KE-^3nQ!VC8fdv8T?KwphA)?Vp4+n7V!Neq@g@|K&fSL z3z-0(nIjD6mG9d+*;GO+zrZ;I#`?5Y#z8-0Y#D>DaZaIbAKoJjh`i)m@7 zW{ne0pI=Q#5ngML<$mz-~p# znsI^RhgDsrWf&9LwwCFG@ov4PyH&a&-fV_(XT0(n|F$vsP-Uqc#H0(<=}?}p&061< zj(HDBKh7hEoD9{t7+y!&jgE>Et^ zJ;1N!zimA@arm^B96T)J)Ls&%)&(0~qR#irC&&8T+!`(NI?n9U| z*!Wob4O;nWj`J*o>I1FsX!30B*0bZkCA=!q56+9=nA{kJyL8wP{RQUf$XZhSMP!n9o&3a2 zjZp{^#g^1)69mVIC93M#g0Fs_{9?{v1b$NdY;j~zLLd6bg+pml`%#(r7vy%Rd!B_z3xNwPWXg)c7D)+` zfwLrroTv$0nRW8M>)7&@-GQIe>g`PUjFDQ|!HmiFPJ#Cl#AImmnIAU-S1#KHup*+e zJRJ$Au;0&Tf!D%JDk1C1{C?mtg>Z3MiX7hLFQYWT;*alnOh3i;kijrd_}yI;LuSx; z3(YP+tAB)%i9K~s1#u@E{K%0#C`9kqb*L-X7>~r|s%*g9%f&Y}m7%_407daxVHcXc z3T4mHI=R|~*G;S+62FI;W;m7U%}6utuw%$>@1cvYhs=U&z*p!WIDG38k2~Kd4+@Io zB|rYzLX_DyOZM3Q<~ViATqWJF>8qgxt8t>i1wOQ^H4&NW_vJH5%KE|8w1`3L9SKU( zHRmRteE(nB4T7dXSwW?;AJ&~Q4JX}%hr(Gy+Z{@IleXJVL-_m)sH7540+trVGwRI) zZ2ni3cFNT2`ki%ze`HWuj_$9bN(v#`R(oQnT2LWzV7nrAuU86QB0ap8qPN!$KWE~FU?Cb%?$!@KAi&wv55 zH=?M}+z@vA-6PVu00h~lmt1R@1Z$|{71t%fi*Xc0MauD>t4OuR{!?lHG-%GRemlT+ zm-{gYjh*`}aMx?%%DG*Eoq@cy}$ zCM**LL+TZ1Iy!uV3as~kl(6bm$p5>PPu>#Bz>b8fX2q=={f$fG$A%WZ757gFTdh(e zN7)|1gDLA}gZ8yFT3*xL!LBr3 zHjnV|OSesVvA#LG{lJ$H?}=yz<<+vo!pf)odB|pFyjOOx>v%*qf7lhLttQ`QZ+hT< z?DLbgZfY@_?|s=f)0W}}r%Y9>a}3Wy-->JnCI|xD8KCE`!H!H%E^Q&t65;{zF_Z9(@m+_v-*0DJHSq`OP93-(%Zw5x zRjg=+FL$P5VNdeYZm_Ur1N2bB>gDDH`r(YwbDsPLm-^Yq5^;CZzcFzaI*dJQPeMRe zX&PJPd~DS=V_yG3rpZ34a{%*k6D%BnbilUaThK2@B8qSJn2vo1$pi$X>h-$Vn)7d= z{`vGhpkaWVv8;$6D+r=Zf@1*o9Ze8`>9fVfWl0;FD@X6;w@VudcfooQ1XKL$zc_|O41ndH6COoiOXaWW>HULX(VyMK={Pl|%&LgYu5_4#DO7-)u-B302P&H=7z^hWu+rzkb=2;7v73qG z!Y?-LXqW7oeMLBtRLX>9;kL|G(xL@k1830O&Z!!(NDnE~;&Jlz<0G~vxD!mR%|Sg) zc(9Jr)UFeYnZfdCIVbZd#!ic9u{5wW)c#rxV+tV_$e8hE-Kno)S<#B>F^$?}kPil_ zS@0>Yt7rBX6#a^zBkL+YV=_1Yp_+bieJP+oc%h%7SdlWCxqYV8x#%+wIBVn@Dw1?L zsq2W=c&7j|Q#sh+!vy@X^&jsXl~}AEwo4_8R`5s8^MJ3@KfM)I?J4=Qg4Sw)1Qhn*;(lRiw-@s`DYHGr~Qt$88;V8 z9iis9qk^D)&X-dc60FX{BK~OJ;$G1fA>63a6@N-#Wl(J(L9h}*sE?Fv3g!pk*6^s| z{PidFW!)}~;Sqh0%cI9HW5=4SLbjNQyBUZ92|6Pr(h}AN`NH73NGidOx|#`X|CYN=7(V+OqY<^0N(ZSa7^kgx{I zG?$|ToRjBs(Y|K*TzUVVXrc1MC}gn2musjcn$aapRUnxCL2#Rg0ED9KFN%D@h=FPv zIg}eajHn=C6LXP7sAD=Y0G%S(3R5VfF!Laxn+Qz4Fjq;n3PCsJJ4#KfBFSgTk|jEs z9Mu(T-BC7^9Fefh(&>hZ^=GE1h_;niAh$Gjz2rov10SA0z$pAicU7(zRyhQ~>;cuT zTan!J?+HFZw$+Sd&CirV=qwApDrQl$>bu5Bg$P)YwF^|mp%M-QoT&oMPNbPg>EQDu z6lD&lkLbh&II#AdlVg0cxDTS&IgdVrJFMDnkamP?TMWi)1gGS^NuiplP}0ex_l0^{l|Ak9y*Qyk{i2@vcOII z2~nZ&?aq+e5?1b(B0s7$A-4nSA0n>{p*h_|a!!MW`-{>Ea7|*>%?Xv$II!0aH$PS` zC+bU%3nncErVF>BlRX4^aJ06dkB6e}L~&tK}GyXV7iD%!yG zK>rC2ZV#+htU%ag{(Bg1jTNt@btRjE-eP>LK|4RGx`~F266cnF6Zo&dR6SqJ8Fxy_ zy^~8UF4Xni*KnEpZrl!CJcZ2A8eaU@Ov5>Jo{x*htY+kVK`a`1cg0c7zxvXLHck_7 zHm3>PLz(_AfbEq5VcwMIgLu?`(B(N1m|>aaoxL{uX-E-(iA$kvm1l~gUxr0~<>HnqXphp>jFmKGV)@4UZ4y-^u|_d%5Xy9CAfSmMJA|-H6X_^^gkFSkdz*<1n$PB@LZOC5hl|hy_a$ zsd!WYZu=g$gJ&D3!J@B=YkMafA$K=2_ryH0O+coiC_aD~W*#cK1SkvV+D*Ui(;$~v zRHo~j3%PEDv@86A<#FiEeNBsy1eni1awWDrUeU5BYX zWF5e+^&oB@1Iz7AdxdWn2FL=w4GL^F>n-GO5?gh-!NLF_&$h=`4n#HHm&q%2SzG3A zs0KBR@WRPUf$48+uKEmceMbv_2m!w=$f`u5?8XYC_8KJwmLIDzvkA!hWs7;R|v=cl@mebjxA-(y9LbDe(I1s}syUP0Q} zkfxH|*lirp>i|X9geg78Uy5HjES)H@SGVqzlQ0z-iPQgx#<7Q28lD?^X`|9K1m-AQ zS0Qx6=qqtgfzxAL^>r@L5j9;Sik`==(R9C9#Nm%R3$&D9*+H)hK8G?+wI}5AHVHRV z5NKr)BmB_x6L)S2OCA)XG4w0fg&U9TI8VK01@QNNU?1P29c|3au!rp_POJDD2dv5Q z(F30<2^Mf)l_Ih#i^EJy>M)=nIc4Ci8?;iG(rCaVZnaCP5~iaF(2t9P^tRc=TV?St ztW}39FB*17U7e#MWkhEJBK)0#qdqLtmM7K*nQzhbxfU^KM2yZL{_jy=j7J5Tm-*h7 z-gmUJMI8v;Np8}QdzOUbltk;9ByzhTXUIl#1-8aFJn}7Yx5x(>a4bb>iIVE2Ofovn zBRv;5l+W))KUks&YnXn+&}$sxWP{qCCG4ndacrbJsk0YLm!hUq=S54N{eteg#0wW*Cp z!-dyWlNGUQTWYbzehVFb<_=r-0?jMI(R57tP)8y7g41+09Y8=H5~WKj@9p?BMrOY) zK8K!`6=aNwOcqhnTWH3Ze9^xgA-P5`u?l!St*ZB=x^xpbR4TT9S;K2_yRg@lPaYx8==Uw9~AKv#Pv4CFsN^q_lxJ}fmw_lvr0F>LQ7ZR24g!2PexPq{w#+~C5nVM!BDpvrV;!G#zQy$Q z0`NwmdhisJR%Jw4-VRF^(>h)nuJn3s_F-ARn~oO2(x88?J^Wus&a*6+SOdIjBbMik?Ll+kU&`|(yqPj!NT zoc9Oqp?&v_WWqvL>$%&b|43VQh14gGXIdnViQW#qqd}ENjm1K_PwUZyj8SyXEUu^4 z2jk2cfv2o(oMehHfIx3yXVB}>3t_SFjZ6=s>o2<2P*X9Clmqf#4)#baNJpN2zGh%Q z!@)c%1|qHu1(j59glKA})+mD+eq5GFf)>Bv*g8W;C|v6U{FIGShNU{1>!d-Gwq>j* zHoT7p6G&qzS-_(464so3*eALxXBMF^lvxQ0N(NEaPJda`Q37AuWE@rKa)6>a3jRJB z{-0Q1rvDr3%gD~b!SO%n-v5pDW&fXmiGY!viG%fj!vAlqZ#)?+676>Djqhfw&DQ@p zr_DB6ORjIyU%g#kZg$>?ddqpk6XQwb%v6=*;lsGsIx0OlGwJ8)=a?OUREL9^($mq= z0HU5~7)(rvX3WHD)ZktU#A?j8{-GI^0wdFi{lhTt;DaE-Us;+x8R|gpJ3Bj|J38CvIXmwcf0T-h%)srMnSj$Z)-wP^P?4I7 zk4ONLkRGi5!5KXnO$oFD3p4AhlOP0ECWfYWhN7ShZuVg7zhi*u9P3${KT%20KYftv zU0Ix6zrxeo8v}3z3 z)-k_kn16GhdaD~x{Aj!|$jJT6lf$U`)}{s~@I&|XJH^*CxB&lshO#<2f7xH)3Df-E z0V)0#;-T~{O@HAxXI52r$7f*#C=d0|&QC2*Vd9+_Se;tIA-LBwfrfc>X0Bysr2nGW z8k-tlKL1Ak^n#PC7Wh3OHnhHr2#)-OROt>?b4^PlRcrsmZEcOe;*|eltXf8D_TWTQ5+IMOvYv;dT~{}h(TH=g|h z{K`;cs(+n?|4JVBvVa(V`1NMTS2iY*^M}O$>WB@#*PisG?*0mbLvVR~&eJnA0Gw&0 zuK~zh=~MyGnX~r(!fGS3nwm0tuKG;=%u@e8|MU1X>i ziubT)_nDBap#8pd-ARhr$s~NX>0hq9l0E9XDZtliXk`sVE;Cniex$uD%A$IYBS|-e zrtApsi+e?2PtCm|DSM(&Y;5k?n~Jfxh(o6ujI@mc`N6Xb5(pN zHABbc#&j~$wPgrfT>FpW7HTwib~&0&eOL|q`w_jFz_YnQ5jdm}k8gx8qO%v;y5@0R z)kC*1M>so_Vragbqi?=MBFg(sBIh%Cw#@ernzZ&yIsn<1WlMy9%$xP3bhu2&# zagdO~x-eBoKIc3FZ=7r#jga%r`75C5?RqU&v#WzX#Gs}?w>xxE( zO5rkC!^`Wmotmu2KlDb^8mS;uNTY>*38{h_foRMXzfatlf$T?n-6Y*aM=(b6CTD(> zKT{j)oEX5jp;;CC2R|NsuJGWFx+9qQwmIT=Qk$U8dU4d!k!3#L9kWDd`fwSbfd+T8 z5i09bcoh~6_107of-5|ZXS!n+j=$O_Zxm+lQr?Eq3%xxWuu0-1!<(eJi}rrQB) zEKz^zH^r$`MZ%UNHiHb8XgsCQH^3ThkC3H5Gp9u0VW;^cjmt~IRp4yWJt>&}`-EZ} z6dT75b2po?=IpZpXnrte0DEB~LV@V(y2#R%26Qi=q=#zcl z81@EGREI|1?15MRS%RfW*)tZnjC-9*T_IPVP0f z6H~Tj_ZAq7PG^(Tn(S>HCNczLiNpk0dZ$+5$7hRkCRr%ANaaT92|As=FP5$mQTWA! z=@_~hhAG+3*;EFYer^ISZ)O?$I@)qgn_n&nS{6h8AA25Qom=muhwXK@C|%DKi?aJ7upB=nK+E3E#;Y`y9d%6gA^yB(E6Du1?tWBLiAts-wIb>vPjCurU;N6Y~C=t zv!hxxRAOlW5=5O#lW8aoa{};=>cAcs~u3boYEQ=D};lx`Am^b)8t?yVgu`m?y!L>-5BT(p# zFYLRrCp34E7^yPD^!ESWDeUV@%qec!;pvYV)Pk(127_ohn6E`&nII!(9Kwd?y8Dk{ z+?lEL36&T~cKV-F^I#npVtiYx3zqjfXXdJS#=y4xH`z}!$F8XP;l2|+46<_btMQSa zttT@SRB0k~itS@|$M2X77mZizvVuvhkewJ-Og2>khMR&!9)oRl?KP413?=(NHPOA! z!_+578xCFfvagUMS^X$Y3D~#msiQ=t+neRSR-LUV{RQIX2zQ9z>t=khqxZxF;%{qG zV0)yfmRrD-d{@l0Vs|BpJSh(#;ZS2tXR(`QI@foI6QWf=oW6*TO$0S@2^&aMe@mIFLx6u4oBhZIiD{_f2Wd9LsK%4Cxa$%bS*h$tuqD&K=kz+%QUS zWzFWEsjilFTWfT!6n;Z;Ko?u^k8-)NIIw(=C9{W|i8cAOaR_Rd8K3(wp}Ij*ec$ZE zP?gC`+g>ey1?GJeSIVfJQQ%|dsO4=qqU3d>N#h0M02N+#4I-X#ADfi}>pSABf+Qk( zj{6HT=(_Y^tV9Kq+iP|#^jcYpF0Pq$7|q>jsF)++A9^?+K&cDXoMmQ7H$dTa2Gyj64}QFqn>=3mKhrpu(I5?R!WCv|OxOwlx}b0DEUULxEnB#;0mh zPP~KwMXZ%+neB7HK{TYVT3?3Kk1mj&`J6Lcg0{1u1PiIw#vX?me9(CR4JOjK8N|ZFDIeStaT}5{j?l}IzP)E5 z(L9v}_K#Jk8Po$F2}2-HOMs@~r*DX=4E^VmLBo&3)CojW`xCPwD>hNBSeg~o-Z!hz zcz?*I1UxOr#$_MA^!S6cb21ACO`uSv1i@B@4d|40P$eay1%-w%YuB)&F$~OTiZ2K_ zbZb0$F%^>)DwT3Tn0b+|Kl}jxOhc35L$sW)EKoTJKX+s$MtQn0_JpVA5-3H(R3NSTabjw!_ex82 z=+u4s)dus>uHyt3Vwn-8Rk5`7?xB1kp8LwbZH5Muiq7Anc!9crixqirkD4?5uu44YyT9fnhqdT)y;Z+U_euQ z1?^neUHcqn-W_0z=}gH&aO2{1NSP^^EQdKT0~8~riWlXXqz@hMdAS3N%HI+6pOK1F zf@U^yL@B7jn@qP);QC=Ggvh8*IR|D0ScXFOT96X;+A>}+!@=!@!u5%u22+JhQ8(!B z^>$M5-04Bg$drMO5QEx>xfFlMe*{GhoS^dkUO~K^^S!6wc7GI6aBFAbOR*VP*mCSh)>Y z3k7&umk<#}%qbV1X>!56(`Gr=m@9ePREFy>rs2F$`(ab#P)Ah6q(#h@Z~saTuA!-x zGSB0MW13Ivizen8JynZONY-@#*9!=1W-t(XqTLfA1%UN*O{kQKjz$-H*V&;G(i}hES;X@aUZo+vhomN%d;j%^OWP3?UiFiEZ zc)5c!4qVQhtP9e=r7L9%xzr?7elffZr6Z!AgyWLTtA3#Y=iXzGgD7?Fb>DO7%*RAC z+m=hfCp@g3jP?vd$=MMDD-%xWM@4V4FNkvOzNkz%|^Z8wF!&u?A0zxwjyXz!f zrSNj}C=Q3+N=>KL{o1L~U4|%0b5V0`rpXfG4>Ltj8s#T@OQhx){ zNTq~oZgCj2d`<%2>UNdu@8ZQXwe4V{XL&w~4!>{Wt@*@gY9Y}_;Vev%k9uMZ8LTck z#a;$P(Pt7fg0=eK)andU28Sn80`A;h)?eKn1vXMiN%-5dQPmoBb`L<5wBATc?JC7m z(b*>WLb=`!u;)m`neEl+mZ*kMm4bt!gRHyEl?lg^ria}^G2FL{A#WWHX=4z!LltwW6YIycQYO8NOeCh;GC-DhZq&Mw32 zleV*8rc)teO4}AYY7q^eBGze*{rKbN%QF1!$Go2$N;J&87!bbvDUQ&Y#)0@wj=Y-t z6LJzqeU1FZAT|xZI(Iijdygq+{;k^)}Ma8pwu&p zdfS$sLlmLoiTB7J4dAfpHWh+C*OY(v98`6815Ok(? zUCF~N6P@L63qy<#K*ErWsFGjljz#>>T5S_@)*om>9y?2+M-lNrU8&em-FKd|Ei`cm z3)m!_1<>vk4@Jivnq|f1%Df>L#>TR8<<~TRu(6PLC%tbfo zuLLEGBqI8$Ir8T=4B>()S{7R`*BR39NqDolFETL){BW5Jm2GjbMea9NZOdJ`Kbb%R z_SU;;qgcG=_LE|AaHb5TQNU4_RMPavx^_ulXRjuc>DAy;iFGj0y;kAzLf|Idd!sq* z!2S^!_>sc*bm`j1F#sKWyw zrPN?ZKMUfs0dxu+I0;0cSk}4tJW?CsMCCln)6N+gI(lGBXrk1JdaT}9*63%^mjKuS zfd%cPkIh6?rDf>4Qxa=8gbF8a1X-Ew;ryF3eD$%i&(QO{kP^q$-VlI>;pj=A;g6*; zNkHvI0jWaW@)cY`XgC61-?V1xFu5;ddkk0lnh2mF&=`=u9YRADc1~ za}}=+d*b>Xi0UW#r$N8Tr)&L!*9yT*H<8OUOk!p2{%g9NL!xiCW{nhZ^B!u-i^7{1 zVg0P$Y)k)y)ReQgGH{NZLN!Y-J2En}D&T52=mRNJ*4_%^g6Vv7Kz>zYn0aaB&!HrF4>+}&nGBtR88@Aa$NL%HyOApFfx`(L#tHFW5pydsR3<`R-?>3JW`Jew8VD zvk`c(NZ4qF?2q@`Vu0THjyP|YCMD*q_#T2S8~`M$HF1vxT#G19u$<-^2+rp3;Dx@2F^U?LewSeI=bK1RQNUoy?frl?b&74Do1tg?o2I z6pjUm&HPVaZKh!;dP3Y9(yy@0`EhJc(4{QOLMP=Lk#lV1JN13k-=l^Q3WA6Anuzc48@-j@><)z1v&|VkRG`P#l!!eOciD z&Z+(CSQ3hFra-$0ZC}%`{pxO-{!W7l0O3ACkJO2T8ZE;L_aBp3{Ady|_B0$D7Gs-T zX){c50E(@dt5{7KVx=SK!NCtYRC8pnSMJgeoL34LDXS3X#p3kJQ#95K7oE}MdFZDm zMi=BPb9y5*+h7}i%@E~Ln znJl&!R~oAq#f|oJl>x`>Q*hI-C>b1aH-Vi7uv!1wauRAD3M)BjZ?d;tOfJ=H6bK$e zj1zA#x(;Y%rDOIJQ&iE-(`+iHdnV>hEv zp!a5D)~pp4qhANM9feiT)^38=Io?>>+d>n>niz&6FK96*{2c5;i3Rz1sJi z;M7KI)YAYnJjLycQibrzUx;Lp_tYpt59fX&jemQ2Wh79{-!FS>r`#86n8$($TH2&U z)PdRm@ud6xOnS6)Q`6@5AuivmLj%rGT|n<~`VcQ|9Yc1P!sDtFt@;|^g%L#qKkW)f z3A=%7@5WgFMnB<6Q(!*lUdfw9P0uoXn-RUt1Y2D-&qkGtBiLK&8x{z1f~iMJd&%0pg)B4wv*PISM?R>|G3X2K$V~R7O7m2gcOx4%k<({TWPf1XB-NC{ z{L*7Pp&DJP69z`UJr_u?PIC6WqEr^Lfu_ghq%y=>x3Rbp+)HTGWS$@zuB7}+!V;1# zSMyP%a!5}hjmha*R7mUx3waYKTH1GSe6MNCD7PP+fSmb)z!vGM%AA4Yt$jY~AjSN0 zVlKS%_-DDQ zIdQu|SS37)NUsK~9#qL_c6)_uc364ugWYz}rB~6@u4Uegy$NNNwD_n-f}a0d|o{I$*pg$o@@EvgdPz@i>n_r zneP4EWfLAGgUq`3X-3Gd?A2n|;pp8;Ff~QkiDgbhYe20i0rk=(gLOO};{sg{0oZsZ zkKs|Ts1IT3{e48mw0|LV`R&{8x7dlWQcN-sqD8#^i-GN$ev!{HNSITQV$o5p#rL-8 zv|#KQt?#6CjcV|=wR^O^LJn}wCt(OH;TFH%f=5xT@VW#uL9qfo29V*@I zZFKh7Q`1)}35<9hmVCSmXUtP>9)iEq+M#YRecDXffBtBt+R((#`b*(j^SNs($3-$z z!!|Ae3KHZUGBe#=4`x&xe2euBE2cj@Tr6xbzZ`!qG;Yi)xU)~IB6r#T8k#3MBfvIu z=ztVJY8Cp3l8UGB_ap#YBS2@)bv$0^Zq`v@t!^N-p2Hvcte5L@6enBhTb(^;${zyP z>i+s$A)=uNWFh`-PPixN7Zx}O+54$V!)YGHfZ>4yu@caDXoUGx1hyRw;W2K>FMUvK!Ln&UGY zfQ9wAh~o`n>OW<<#rk5~QF~4RbyT3P{Zo+`YpC$AxNLs`qEgaPURW=tpQaLet6)q2 zH19CJbA*O=2jc9{b$5iLbR$aJTozzuL6Zz!XsLk3BW_5tePpTWghk-}%4psh z-rkc>045MBM54%4ePj8W(nQkoo`HwpSe>_;J^ZxFi!ONA8maBv`RN@yBJiswnBiTshWCw6 z`I-DNRV2-C1CQbNMt42=g@NLxR%_sn{)C+2o{T_kL29qDA6NQ@4t%t4Da0{iHWlQc z<+yameht=3qZBpXN$LCSP}pkksxb2|9NH&ZgW0jVp>W|SoqQM8IU2is^+jOU_Gl+M zw*_DEXkfW~^spc!eJLjWGQ}%#EULPPJ+ryoUR*3aui{neAXErFJd~pIuw+8p-lM zLrkRQ(01Q;WX*fsR#mxMAYCXlf-v>~!jd1ZSeXLU#q2R5)`b#Nh3w}OQJ}2sVZYwW zcn{}S$aaX-2v}%Y_`Q4ZJN0$Sr8~cF@1SFqs|L{oU!Aj+7rC76UX z)4rjnKvNE%rlOBS8lD@6q8&m-Y@RN%LrU%vHB2wn-#HJ=+riDxEn1ue1-&b5i$j|_ zyqeZ!q4V*a|76JyvE1T``lA@M>f6^v@=|F_C3%ahs{0g*K$pI^Mra&Z>*Tl!k`nu5 z1)cQmK;6PLm%tzVp8MOM`R zO()T&ZUi#e&9&Ek_QC2zE2~3_+bogxOE$Jog(DJ3Urgvsca6!+A1HrlG)7F!VX0e_ z1tx7^(Y5~6U)Z9z;K?l4Y~N7_0wgzyuF&kkUMX8MQd1#9uWahOr-vmVb5d7fWN>TY zzML6XX5@n2n?#K=D+Kj}5AxibD+r`kxm{N5nf~+vfJJ;@?dQ204bq9k!%EO5lgN-m zHvMbEw;C(0Kxm@9W6`|1n@uBLdiU}@nc)8yW9JYg3eaZRvTfV8ZQHhO+qP}n)~kAD z+qUg~v-o=^VtUcbjNIpq{PN~GBQddV0j%7^>p28B?3nTXg7x5`fox_Dg3kx01OQ=u z#`vAI&5b*3QEe*w#na={$2Gi!b%X18qs9GevGJ4OO8B78N$G0oGWh%M{*77meY+mq z4gAh+-(_1*QE;4Egz?@$;`CV(6V-2ebm2pm!6psSRX>UX(^2(cg)E3gT2<6cJ?Mi^ zb^Vx395a>jtBj+FQq9xzzp1_N$NnMSCM#OL2Hf_a3NtyURD%xZcZF9#yPg?uGX5)8 z0DJn~3ucPeJ2GEd>=|2ydKBi8CR;er{4f1RHMbfz;iW>9180kd6`cGHef|Xaa5y%$ z^s6K!kX;g*3&A3-O+O*9xCeBWhkIJeugu0PBABARnDT4BuRz1IZ2Pv9{hzgINo#?l z;JV_#)3l{gM)%5!cXXZs-vin!^h=6|B)UjumzQRdF94f4km!2#91}>Cn?hMmy)7X3 zSC$1`9J?*&6am4WSNjeoc%3?BgQJ7JrcW@idh0p!_2LH$e38M!m63J#Qh#%njd0{I zK2K&TK!A(U=^1#ud1SR$`SP-$cl%xwFk-L%d<4*Vv7yEON*9!9UDERY%;*!pRcI~& zONAZ7&+hNyXJth|?X!33Qs|}(O8iO8JX3VTcl+EK88e^SBc~2qy_GDx=kzgFkV%Rhwn{gZrw9RD zO=#ud08>X{T+=InoF%ZV99V)d9HROq&8eIg-@VxSzAL{FPtlgDB?F7mFvBvy8rOQO zX21yEUl-KX=P-pJ8cmFa0bW9O&X7%~e%rrQ^UohFR_|EqvnP7S(&#uDAXR_XFUoZG zj}OFF8$%Wup0nEAb$|i4(vWMm6%T8Z+C0WjyB%uYV)7j(9*Rk8eGloo#z^A6m^+AY zE9c1pOP7!HHLedZ}9z6g#*1X+CbjoXoStuAkDleF+qfOjfg|VU&%Tz)IyKPtq8fEyd?e9?`V_7 zfEjW2s#4sPZD{?GC`;#nnUHUkX1V#}nid$`J?YQ3bWkQ!j4d|yg4?*10TWm|Fb@zA zA?3z@1d$rbl_qK6lR2FyP`>0)U8V`_GFBZz`OVK9C~c-0COOrPXUrmPZz zx3qiwf0vQkfYvBn+--fzz>P0R+a4%mAb}3lz;}v@x8pH6S(`~^M1mr@ybr>;^^JFo zi{<<8!EZGcu9BXbA&cR{HRA|YqiX4j&%ZiXb%{lt=iQ%XFx1?!mLo)(k9rJEef~- zAdhnRQp?+qZ3Z>73-_eR+33-0^QkSMW@R}_FQQwDOpvl|+Rm~dEW9MaWnu6pC?6v> z@6l3-J+lE${=GEeslUyI6 z6piIh!Rch9@ZGHcD#upn#7TsWXoAn>_gx#rrSR8woCV5L%|aEXFztujy=ThPZ)RHv zczEx?MY&?Ok0W0>AZw>?Yw=T##wa$uCn!YdL48TzmDoNTVx96Btae~4x}ZQf`3K-# z&l zWao%I^z`D`7va1xnpbmR7?wovtz{Otfb~F6XkW}Z5%d1zT}9*-lpY|%IYAl0)@wPF z?z~KVglf8}zGV?3Te;`A@Z3{Pm@0o$&8Xrvew*}R^bb)4BQA|<@Ah@gA!ry!%msh0<8?81)sNHQiDfg}98<8wP2%(&)| zWm4y01G56r4zQLQh%heR8Zx~0q{YH8o~9bMEs>%TXnU%Ky=;0$7%L7VXxlliZJ+jP%C{l^ZHYPHC zuR2kek9sEWWau3(ezq=M^E++Ko!!C~En#hy@t&9VEh$~C7zEt0TK01n=!~a+L5edW z(=eAzM%0usJy<~!xoo|PG$p)uBW;?5Y(A}vkcohM(L@kLyYQw0H^V&IyL(zyBldOCwW&JtPtmfi z(Zs=@EZ|1dxuppXfBb6z4sZLG$p}nlVIN^>fNvLxGmXKlfc$ygRRZH9tXN z3fi;ix=mG8B^AB4;vA5+Kd{{gq&Ca#8^L**YPzh>y_4vElY)HZg0NF4kKUXv2Ag%l zVWG-1HIIh+0%_asCj#C)?N)t}y|6VuRc&!TNZA$4c=da@o*$L~b;LSsT89OWk`*sn z<5V;1 zbR~b=eJ{AlVV?ns7sSU8W=y_5aFX@go6Ej8{Sac$=XR7- z=-6MvAaJGtNscs*Hu}yfkIh@>EvM1KP5#~KrDt2k#LdJJqBpQ11;pTbqV;`Q_Eg36 z*Q-8X!T9}uLt%P(g!8$2Vd!D0{g&4-ZMX(&^WJL?AUFqyKe(A}3EE3+oSA4Kf@^tZ z=cD2lQe?a6S1#RGeD_84A`YF6rV$4 z@gML-r@Fh8oki7=BfstUh%93DWgsszNzl+4k++7C7>iit!oKb?LBnuU>Tt39-3c)| z`ZcMWHjoCs8j0Ls3&|1NS4SsGr?W(kEb(w_IRIXl21KQFf;-C;m~oNgpJ%%@yY;-G zPYn^3ZNFd{n{RjVBBaZan!gEv`qPTM5tlh;&m@kj7dUcXqnAJs4@GSGi_n<|Hpqp| zPaV&njJsuQ@*VQY!z3@{TJMPX6w}#pUHsgi6jj0^%X0+>Oy;g}QuM5nO!5klp*u|InH298yV-jjyreQ~F;21bZ z;EES;-E-<&^fA1x^aqiKM}Ii@xTv;Nj9iN_(v~LlL1dlpBpaJ1$5UTzB&jRJ4+n*C#2PPM?!62or^yOJV5K zvQSB#r4tWTlx^d$_oo_*`T7bXF^K>yAec%_!t63wl;BlMirT6&0LhUFMa2VRfvOrPyVT(QP{j)r+y+!?PX+MW zD7Y!HjxS-RBi==tt{>0A!qGNc>BY84tp$|J_Y2t467fx z-ounsDnp%>CAg`azJGk{q6XUHKoHw_AUmp?m;Q5!~#q{yhG@?rff9m;o0;% z$4FTTmGHn7HH`JDWP^ck&5AF9x7{=s;2R0c#s0?ISZBCUTyWqgAd(YNeQ1S{&yLRA zjyzGZs_VVBx}2G=v$=s9A%{knWC6s=Lqlg88cO>G!y_gc>s-9kg(g+R-ZO`Eqyg+9d()S{uG1c{U)jS(ma4k7|novievYN#im!FfeIAm7IgX47{lzXppS>)=aI4Lk1yG2LhK)9-- zmMl#R*93nWlw^rLI`*!BMww_iY% z5Y_kRKu#Nxrl4-R4YIDk$dB)VDSVV>-u(fv$+rdsZhu@$3*J@JRcvo0teI8+uqkWv zw}2TrY6^wss>{K+fO0EkWe&A1M`<#h4|V<8X@4E@q^(Q>0<=SZp6TZ|$;<8YZ4h84 zpmgy)OAFj2ZCiS}d0yBvx7V4UeSC7@FQ!U0B)@=SJ-D6!cUhd4ju~=ZfJssIv+aBN zRjkeKid@9+)2F~lCB{W)KfU8F2Q!*seRAZAl8hwm`xTn}uA+COzz7Lvx@(b0F7};g z!cr;HSGBu`u07VjwC_3eCOocBLV?itakCsB6JYY6?>X{fBP8UKQ%Cw5O?iKQJZPP> z<@I~c+JBwdVjvi(bh(XY$2pECCzB5xSkMC*;INDR1*}MNl>bxQ zDd5BUsZwM&m202XS;)9R-ui1Z4>y^~C6-?#83ez?NqKsx-tClDdw!xQ|59?9Q!)SN zpenCRc#p8*iC88hN^bo+9ONbZjVRD|ACzji;J%l|(~!S;(+z5AS;H1E#G+Ikyb!}I zPua5@)iBdOt#u&AuaN@;)sHkXcOJUMCEog404po%B~ZAdb8`Kg^QFLj1-x^3ga)Y2 zSc0o}T<0iWf2WxOmh#F&oZTy4#^$EIY5mX)i4!R%%V_)}n}46R{YThMuZ90p%`9Y( zPBd-tTkmv`ofJK(bhS8YlqDf>?v0-ee-pe|g+u3(Hs(cpOKiWot%}wQWuR&;8-xm*>pPnf`2T%qPnZHG`;wT7l@>oD0 zmp1V{_#LZ-nA~Pa#kpvs;pN8at$}~wVt5Hms4b9r2RD{;L@z_1yH)i&6xQ(EnCu#U z*SCE4=oPYO=OO&rt#F()ufat66SUG)>x+0Z-L}FZ24THSVSl+hd^uLtBpSXLjBlO3nE zF9XIiJARiVU;=lBp<3YLY!3jvHIq7NXF{}d(5b5%Og+D<*2tC4T??U%cTbp!qh{*y z)zK-B<~CmnbpqJJ6~|&V7uXksG_-4Iy{Mv#woszBQv?UW$mu|6$QE}+)ykp!wZ@7> zS&R%Fdd=OfmlD-57{*IkGe)eoQ*SK#ATSGo6d4~TekcDv?%{}I zC)MZ5Gpj(6wb03vH(==rH>iT26e3_~?ZCEHAsO059(DAT+bB0?gb6e}hEX{C;F!{> z5oz@FXG4IH2071DULj@PxTC~uft{ua(aaQ? zoO*!e1o;aDtDvh2u9_&VfSJA1o991w&Pz~$_7eM- zn|s&6G~~#i*>Ry8Q+BY59vdtUrz{}Ij%{sfU6J(2zGw6s-6iyW@HytBJ`aMAFhTwR z@Ww|N1MyqX$B8GqGbo)_hkJg!5AibJ+IN{Euj4}%5cx^lXl!81h z*Wz#3nM2X&p%ET&^V0g8gsW?LD>*Ke!!wjz@HU(GqnrY^(q+6OVo@e|>Y%<@K4!+z zg2~s++By6?oN>qLB2V4fBMmM3QWlSXEq^pn6D$lQ#=TTwPlr1NtLjR;`vnR@P29^J`UDKz%Z@qPnch%s(lu)~`d z)HZXqp}7eie7WZp`Y@05+0OC`Ue%}aT#%jdpp6CJOv#e7gHRH8^a4-IrrmS@%bM}|Dv zUMe_j7)6FHmuGm^q@Ro~n^m3uoM{g+Qy9T+vht`(JRC@$#R zZ-8nfc%m5h$jTK+a^yK0?!jA)2-s6%xi}ZR*em}?68BH%_{*A)hW3?;-B1Sjezc+# z6kfm`DLIrSSSpo!9eKRz_{oDQ@{V_|va$y0Djg_$%(#CJy?XpjM|MJ9k?7r=zZo+3XnqjpF7SAc16CO@w1^$vA;d&fw*BU!-Ysxn0eP zrbU)Gkmu&l*T>oLpC-J@ow(7IWO)*3{J}yW6l=ihJ~bgzi4x>ZX?18_1Uq4RjuWCV zODMs=!BEl(vckj)&WXo8jLI2OQ3eb2!TgxMPjs? z*scE<%;Qr5vS@@auHAtm1l(e!Z(HC}iRw!Da6+>NkWhNHa}P%<5}-9q3;0YC*z!m| zV+lvPZ>!3{)%BzEBWYr)w)c3Ch)1fP!;f3>BtR(~Y>_yiHppc(aJAWYK1SysXiTH)G3dSN{p)BC6?L-~8WcJQMj;j+JJ zsKT^;L2#i)By^SP2I&^{4{?-Hl5&es#U{$o@d+Ajz1A*Qvc&tjyc)<~3VqK{zToXw+{&L#Wd%VKEnJvocUF z=7w9~G4m8j6&)W4iuBy?1Ye{ESg0rc6fUI{ij`+*tIpMyN!d30}SsKvW!AL~TU zhf=B=TkLM*Zql5AMp$^wkL5NoNtA^#&Q*1MF<#hci|C2z;_GclwXrdQ{SuA>5AkD8 zTZ+aP{dhz1Y{rRMmJ|+>fy^^_uwlzI6VJnRD+inrNCHb8uLxPeDkVelZfSw+(#8CF z4rtH7&>ccO14yZ4>jI6tPVqNJ0+iw7O#E{~oIKd{O3Nsii0~zx6d>fC7(r#OV#F=g z@4ss4Db3puahz5msE2q2fIH*Q(Us&Ac#vc;EO&zMjS1ph(?0dWmPs+p>rD%)_G#*~ z9BuFvS@^`8650Cz7fW&qKvJS4_Y=G_`xh-dl91683pg7|G?WQiXVrh|ONcJlJ;7AA zp<9fRr%=O8qIP|o*LGn%o6S4ws-*o5#}Sxcb9aF<*Sl2<$;|oHp-U7!Gl<4{BPcA> z0>(aj>o8ZQ9L&u7?nx7buT{4FM$wn0E8#ONj6tGT9O$|3a!INF3 z^M`^-ut;*m??U16^`$A*$Tzy=87?@NxjL)7Xu{qrd&l|;kL4uOPz9n>O)yenjh)0A7_g>%iKzuXBk+XmY_AAxk`#SXtXCSPYnQU55Mw)|D0eW$Bbw+IOYL%W3*TCtOr~4=5lWO0R|DmQ@&6{ zNJ5S*O<_`jwd+>^%-H`GREf2+(da6^9@XiibH4I?QYml{(YqP`H1D7w<{CN;p9kCS zuAd8t6ZnS>71~{$^^utK>rx}0cj5RLa zPa8R_6k0{iEG$2mlurlRs%(qB-ypZ&TUR#Hrz(avwnYOv|Mtu!(?Omdw0dCZJxkzX z9fO@>KEF1$x^>`jwW(M<&%jP(CJAW}9qDhWyK}K+D54cr(LAq}3#8CLc%=1W+mUWa z&;tPw*+yX$65y;N#T~JTXO;Md$8)~zE+`|A##qa*t!Il(XFP)Lib+fEh1CA{Hv;xya-CoL;E?_ z0%BJ29ri71idgyf7Gx(&PI?>Kw&8_EC$s z$Zqqp!Y=qk*cG_y)LUhoA32RQQkw<2`0sVpNFgw5Ru7p%_38Dy0G)VW>Tp{0M^nVT zwyI>5xJOOo@Il|}vGG;i7CRydQT6!=rCO1!sJPS?@pPHaQFY7kTqZlwQnw^aisj8l z(_tof1Dzzn?O!`1 zAUB2=kxbFf@2%{KzXrpUpAXZ)h#-jxy6S{-Pb#v(&wy4Qf5Q|hbU-!s8eVn%W}<;f zTQso!h?8d1`T0lUgYRbIYY-o9*sRz+2skDioFBsQL~6+2?=_|p-D5aBEk>5#m2-pu zC!hr8q{bZ#di>%@Y_MM12h%;VRS0hlElJ~$!Si7(#YtB+ndu2XW1yBo)nVk;C8~~h z1T-?&>g?Zp9hWkX-#1#sfB?0SPD}S}7QxI})O7w?!na0wO6eHutPE3;+}(Rrd^Ku<2lKZe>YP-Ep+RIIG%zjj9jZ>fp`rq058JRRN? zomQVUDxIV@!a@t)Z+!NuN>c`MOIrB@N35U794m$Di=mi^UWtxHZ9Ei#Nw8pUioVaMZo~ z57zI+Ua(6G52imjbQI+upr>}y;^Xx|xz4nSkY*Qxpo^y@2x%0}!!-=}au8gm5W;!h z4Q(8lKxKcA235qr4SMR)r8xSo`pt`&bT{~L;ky&R>hQV4KwgA)VN6VKAj%qfchdLN zhw@2*UOKclhB(}hNST2;9U*i!DNIPMQ>x{7cI-^M`g^|9A!G6UOTvJMxqt5XE!O#Mw2U3Gvqg4 zU@d$E7w4V~1W5`xOwY&%=3FxkA@JJ{zCO3$GR6Lx4gj$(wy->|stC5Eo-m&gH{x}n z;PzWKDV|MvZ*N$lw)^;N1z@&7pvcZ@%bS zY^1;>M$@q;&=;W+|YV&Mdd zKt>{~?lj`%o?!S>$}Nhy z+%wLZYRWTr(ta-E6^1yS|V-F$>-kt$uFPC$&F;nKNX0CgRoDBjg#L9ssURCSv*>%_JP zf}M^@x#)ihRv}1ur~F~C;pGSMu;2l=cGFFvEKs1v01EB8cuJRm6V;Gu6je1Mu4xi#odm@c5gF`tHkVe#p?e_kis+ryDSq zK#OxHlpuVDWx9hR+955|C~`a7s(jo{usW+=V96a@0~aPV6t-No&T7|EAlwgSl)p2k z0W9i(LFk z)?v3Le#!^ht-krkLmMil);x_~cXguqIbw_IL814^48HfYVj3bI8T%B26Yjo*g)+sYDh0`j(C*Em81i%PQ?ERmH7vTA+R^Hg5u%%4=RR$ zk&T(@Ka2mvlwthO;vZ9nf$hJy{&z?jTP14+WOMW%3xg#UEm{@Pc~8-xNC}C#qEaD2 zi8%^FLP3G*4if36j&;~?vp&z?oX4EgDbJZlyiq5g6m~rEYkg`}WB>*zu$RwmRSp%vB5#-N@;LxQ3r?+&^;0R>k+U$zg7?t-$ zYYj09vNr8l3CxI4(;|w@^D?P(@}f3e>Ci_JF(8T!K!ayD$bGh>MUH!%pp&f^=SZXy z!soy;6T)Z-!}BQG(M3WMpulDPbxPKf832MEIAjb6LDd8{S)i2&EH}RoKZZ7BgcIQW zGJ>3AnL!A!`18X~h(bzg;=&ZB^CWm+^54=3G~z8)m3|oy!5@m8afOb*F(oS*IA?fx z7xYN>?zx-+<4o|$`%WOr0FaWNkcbbM22C_U36+U?OJR}$^!%SYM zx;ihBgk+l@9UOt~H)@fwm$lj5!n(IkwHyAuTs_8o3k50SFYvT}M7ln1w_ByO`ZCp*FD`HH5Q_gM1?)4r5$^srW*)%+&4UbfHb+){T#eL-*n#KSDQTBQz%2zD&)sL zxOOFZz5nvKXY3I(jyybaw88oKL!7k9bs9&p=wEh}V_US!k)^{8@iAgD)H|PIEy~n9v*t-)n z)^yu7=soHv^QM`$mJfAz()el4R4tkld3v@^`LdN1rl1+HN-K%4_}4Yy3B$cd zLF&JL$?pgmU8BE>=WbgeNBUNHj>og!-U@1;l8oN67TE?RlD1Xe)B69OR*Tm5>hAs< z*Rk;bxWPWU4m;HcQr)vx$Gev>5)mn1sWK9`N@=r@Y4|uw%Qvw!#NZkr^y7^8QOf(0 z!7%nMo+B)BY@~bE(SA%uK`A{yrYfe1Hg>IA@U3n7P_#$7?q+27mDQZAm8RMX`7Um{ zsSExr>sn1+Xko|~X=jP7ZSG9Bkd48b-$vTB3G8OCbBZ&0$It%Ad{AwDu3(GL2cR#c z?>sw=w@YOkL{mI#N?6-)Ec*31TW*I_mKAEZLRYVn`x&}91_iI&)-*;$>qu&Q}@akZvOxDMO*(LLDc zp|~9>CC+c(bmrMddAU?bP~fb9FTfC!;(4 zYf8KVhEG(ig9fGEtd|vUe?tzS7w1yrZvK_;%H?!ndhp#&%n92rGuz25Nm1ts6jXFw zyS&}9cvNgMDtT8?0gcRqSaT?46FlE~rg%}+Jsxi{9J7BhX~;ZQ#|&BtvZlrSFw^>4 zOPj5)&3|0`q1mnL9aoI{pnEkvVi)*^&b2a|2ivVJ(T9k#I0A*SLa#}FipTEiCQanC zzrBV3mQuLUw0H0N4xGAqA!^5#gLcYdL)qM_u=~rs%HYEY4ym`B+%>?o+eJ^b-8Lq{ zZ>Ft`H>YueYvhtxc?t6P)ElQCPd=X+6Xu%MN<4*JlRg>_32R`$Z@qHJNe?58L?+bi z!Qp3dHQw-j_JaH4&FzB&n^yHqs~Tuyt(`}hxzka{?iM;+RU-Nv+N)Mq2K@eK^Oe76 z%`#czo8T&ZH|bD6Bt1)|v)_LH+PP45^v$b1D|@E;cFrFk>X)8X7R3F3j5L=2Khiju zS^ghP8Y3$M=l{(#c4p@PPPqSFrp3C0s-$RdvMC`E5f-Jyq=YaCySuwf!c74PPr)z? zhr9f1)+`X^20>6z5=co0hlD^aOta@5a-QW)J~nKxvhF1Y z6WA0^KyZYG$D@9RdRi5CG~SMC6CWP9ual2L6>;C_A|rwa0(=o9tm(%=q;LozUI7LJw0HnsKyaYQ4wVH6 zcoiGK#bI3W`O^a8xa9!wF)}8G`-cD@=@e3A;9|hd0U6^I)~(@Q56}Sshy2s(-T$aV z!AXk4fKkGMczJm}1nJKAK%@k-oC*h!!yH1)g%=f4z*B(SK{E+pUqOAt#-@kB8k|80 z|5`E#tQqqRQcwU?I|Qx^?pxSIaN_`p0ycC5!z{4?a!F8p$(v8}LeO;u*2K{G=z5w0CG)a^H2tbff5fM;<1atuw z=()uW=woAe5f}Pny!%x)Vtn}~LXZsLK?7gFH-{VjO8Cqhz*7JOJB5FI{*>?UB0=Kg z0{}G-1K1S8F>s9YuQys%eCIQ@{ZeG058#B9{@Z=Je0`ljnq+_gx;glc|HP*Sv%)$b z&#rX-4f|?W)Wh2cy*ozS1HZe24g~Na5L66+aNGaA<>@k5yXE>JR)e*R2l$eDsn)v^ z{8s(vxj}OH%0rMF=ufsJZdeKh;`lM_0+oO;3HQDG&VT0_5!eZC{NA7K01U*#Vrk zz~d9tLomqy%+SI#1r0SHYIue7TQZ&RRjdzu3KT5tifFM`PYs3*3iO>0%Wdj5vt|tv zdwh~l#(>4`l);bnE*)kRezEIHF?fxTpuadqPXYr_tYBb|Wb@dVgfNf}&s~O4v5J2M z2H?350mB9o@aGD?LA*f1k5x+r0D$GK^g|g56hQVjEo1~h;L4*r=ywGo7(gIh|MR>rkbv7-t60XfDq4Ph zqEc6T=bFRZ&uP}ZG_G<-`z|3|(sMg-{AGP)dB3$$WS1E11oARqyLlO zHTrTf;aDTOLggC940gN?ISFKzD(cV9PoL%l-Do?b;04}bHFwQEh7@TeADHOirRr$& zJNvA&G*25-g^#VO-MF1#mp+|C8P2NJEmz%@o#xJ|#07$5i)2&$@#l&2kVIroX_~z7 zF=~ydu$dE4#$A?IDRTVWXzn?~vil>dK1S{`@eoT-`50F?`s_BV(()AlONbNCl2k$$ zjsE+|?!XJ#%rGBL`>~)a)NvFNyDZviS--D@AAGg+%N3#cS_Wi)r$v@=b)n0BjfRDE z0cB|bKqfd%?ZO#Z!@l+HGf}g!KK|h3S8p4e=Zj@~6@~|nYR#A$9$LjIROU(D zMDW)M$9zEtsn$omyc_U&pEJRh1Be8V6tF*ecJDei`(^+wk_pdzAf{dIq%qAEDRz>}kSgddslc#$XV5HiEY6Cr?`@8!i!C(@k&1MogIntSR;0COf0MXB z9=EdgJ%rF?YFE*l67N{rRP7x5IoZRUTf+RVK4VvuDhY`68qxKe+g?C%&dy(&O6-_2 z+clYW*YyZ%>~H@vW1!RJynw*#*l)2KntjMccQ0h*zS|-8bO(Br#H>V~!pKsYY=+(4 zvU!hM_19sjrt&E~@vjkPjmO=xN%yUP^!A0#o-3M02%pOix$$kbozOfpHRQ`?8|y?~ z8~@|am=SKeom>%=m*i?G;~?G|gC}WQ#?r`b&+c)OUbHPz*tB!?U9;PGZ+W;NfB4Ho-EM(_V;@jPs0Mg#wpDUmCgsU~S zL1J?A0Z)qOP#I!_lrYoZ6D{F@QyYam>WwZP_D&8!Z zF!~uAh=efs1vE_bKuLHXK3R^pMB|1f-)Tlp(&5Xu(`SdJEqW|`0@I;f!QQpEP7CXH z*@&ul9Iec4i?>i<0G}M_hs7V29<|kCZ*-gh=;p42fZ!aH;B#1?6f&QWEOi+Fgm zn`Os*SAY8nemZ)fMmGE8AF?PKn|Ao4aBqESaNvSo9wDNnAF$_f|pDtnl(Z zH_5d|D_uy7VvWm=hjqdZQu`?tFBPqkSXAri>@B|9B zJC@ZNDarTz@%1z;!mv_^E=;?A2R_FO9Zar~z#g%w3>%g)AR5>jxHJoF4F)L+kL0d? zMRu=K(&0plBSz#Lb#*1_3B?Z;BZ5k;xY-CwRX~gGF9EgVR%HM&*tUT>+i3*hI6pkM zr<)QDvkN<1DDpRNZR;Peex@s~c9)rB~#+Ek&OkW`@F~Ua7Oa(a*$% z)UKMcMCpiYaYKHZ2J@~-;7R} zxhMxtRu$8;;CLM`b2q_QFR!|pc|)hSX3hBs2EZ~xerYm+RMU?MtX_HNxg0lAZzkQO zi4Mek8(|K51sL@rca7_f6LHggl9hutf#O*KSRI~pNpC~?_CGvgM)pZs^1oRIs;UOK z=$q#;woT4P%bl9B>_eBz#mdL=D)m8H!R(eEXgjbucic?0oTHb67qKm`auA)FA7{CP zhMp%Ze9gfxmaKs)mB}wwI?g9AElM3)Dl9<7IX1QY`YK8!U8$;U7Y+z5+IKu%_|o3= z=F+{%BB{xMrS5Mvfr|2H4SS9Iy4te-1y2bH%**ZF;!0k5?_B9bEJCM=G*1WP$?%V{ zHI^){rU%$wpSKp&Ds`9^xN*a6W8-C|$@WSwK0Hx6y^SBr0oDtVe@d9O9hF^p!(82$ z?AcHKlAWG}ehr?grMqG+r$rzy$4C%*QCwM9M$=N{n)%{p-7R&Vw^!_OQ7f`{Wg!~! z3kHzAGai&WZYFW9`xb-d0ptPBFKf|Zz~CWG-ts0w5E5@>|Hit~dvrU1&|B+S|3rA^ zj)k<_KE+&&wYwg`ZKT&V5$mv+&%#vx$(yENJw(eq_PCD&;$ZTkR~aAA7+}w)w~DuC7-=9|*LXA%`MW7HJWK9iV$bP1X5WSA+&d?U z*Mw+Bqk7Iv%CK$7QHVF!Wu~{e;=oB~;Jlyc9vMOo4grR+$PFAWig%kP2p=lg(X$!vIroo zW@1AAbR9gDWFx~+q#aSTDy@7k+^wVKa(EbRcWpE({~-b}opG!A!mDTf6@^1N7<|{W zaUNNNxn`rYKDLkEXwfuNxzdq9U*1#US!C7Y?Jade?{POlpVf!Er2|h1`{0?}^ns!( zDbUx+F{DMJFIE)^9pm?+`jyHv4QOEGm&B_O%4cp8F{_JV64?exB)KO4GHD@sR8fdH zrAx8Dww74myI1I9=ewP=n0%nq(&GQ3b*NWrJ(Y9S<65{C+&Ug7PFswtA_A}ZTsTr^ z9ChM>>WJ(3Hy|)~B9}r*XmMSn6IxN7GruypUh^%1%@*<`^(mk`WEis4_HXFQ@X}_z z1*%GvJs6pl|3t0dLhBwm;9SR#a7K}^-M&T5>Zn=iv?Pv1lsEXP;`ZV|wREu&Tb;6@ zSM;oR?1Qy*RM0Vw!afSu0&Bs3zWyU{1tSt8||*d7EBQn> z$(PYl{MsB~TbxgXmmKPO$)YfHvtPd1kGkOu=p-w z|HvG6@4c$)&pZ`EV8@4)qM;nYDV=PNHBMB~d^&~}ZicYZlV!<5z$NY*d(VWt6AJq} zdCH*RD5q&rw&xFEDIdX%HQ>7G9@!x)r8YmAyQ&e@WUd z(Dz$qd`((q-ZHerPo?X9&DeqYl$qQMxHt`R7s@^ zua>)lpI(fTRK@YV%JIQJyR(jO?7goSw34tN1-A)qe(+C5=60Ql^e2_J$%(WBIVwA+ zr4nxnkGmqJ?DWdGz9TZE#gUh9-a5yqq{&UFzJH-^sS_}1*THLcu>Ulw`{!BEmw=&UPKexIqsZghLbcu?8 zz7~prGH3H(^pWQWx(w`i{G(4DjjThTGVfL00_~4FAQ3rJ+^U@|!t;7e?na5Iu2B>x z2-n`Wdu6rwMa7fl57F;5ZeW7g%|ma~OaHY5Bo+71OoQ#tU%+T6lHi#jqH;XEf8744 z=4IhCu3I*1O$i>7^YihY%b6PgSSguxjpVSN98psNczIM}ZKQ&V;3U7^(neSFAS^n# zE8)C8;_c;lkL*doxEy@W@6~qKWbVugIfR${#8Er~e-)0%EI3BG1ZD>om+A79CIl3x zN+&37DJ3+@8S>QZOC2rZpx1D1am?I|eH&C)rB9}!AWP84g=($$^wOr2(J+}Vdf(RZ z*O@rF^P^j^;NeZVI<=NoUMuvh(E9Ea60OLYiBU?3wvSh{GZ-cE z4TXf#Q`gkDNeWzRVU+T>&Fk*DMib??%{;kv_t3SIk!ogXt{e49!DYho$u3N;f0jZm zSK;qk(nY$@MjYNMuk#4)*}O7xctvfa+dm|YA;lXjw`BEC0keHN=`vBnM#*ijv4G^S z(T1gzHyyNFGON2mpG~P~kF98VKl7mN06r`W3Tgsc@M*l;?6%oG$lNfb#MXH2)43A;1w~2#e43`6pRV4opQ3;EmV1B2M&9*_L@- z6nkZg`7I{tk9E|PIJX_)1SS$l5J4;%JXP9Qn2skmAe3AZ^pS*(#%*IFI^XnyPwJ8- zHSvhgOj!4bG-P?QC4A-tA*+-2OiUe)@)jTyf{_z@y3trBJ@!w4uNxPH95kWVspuVb zCUGrMe>cnZHa2;0R?xjJh}-Hh6A6V{@|SOcS~b zlR-nj0Kew#-rZH0ViBf;ejFLCuXY*ldX>I2VnP!WLl0hy{RM!_H3&Hu>lRCVg>3^j zZxh07Rp!&cyA;3KJ$~fB1Yr$D*Qw03$3>F}PAiaARLWfn;?I(fBdoO9`5;Q@eog5T zD}Hfr;3mAERpwRrRLx}hy{nhR+pPT<8-yJEKDXem?~|`dk8iL#fPXyLAh8hpqb9gB zGgE4HR%`U$sJ!6ANRMEOr+#jz) z*EUQx{d15kFE#;@?J`2=F^N{osH#jL_)~tAzsAdITEOYEWQmH9_N5aFqSB% zz9^ddrKyv+7s z;|Ew{p=}tcv@6w?`236m32jl)cq49GDQ96Oy#r}tloujDuBTu<)j7_A`%m#`xas#* z_ELW?q^HE6SUgMC#|giSQ@4@SQWz^_n>~=ow!bh;f6OI_ts}+a#iXnkzrEJQOryOgd&Nmxia;1q3GJzIXiVK6sQ#w6>*%!l{ z5yf zkb-YWSJjh)rb59KEoqbp2rGlThY3(^m%S-U}r!7@STw*vThmfmu>$G3^8V2+Q|MUtX z&K6|rx0$RE_$z0@SVl+-SaJj3V#w(q; zVbeKT;SA_*Ok&U4G_bf_538fj`An>GKb4T}OD)UHDpyIy*ChA)=sT}Q2r^5m;c)V+ z{b$X(i3Psa+xoHG_|I_CN^@yzSKid8tU)>Lgh@Za)dr8mtb<0Kt#x;4TFh}D*N(As zm~XaBD0PCU2kXu=J_5$stu11C3o*GmEV@qTcgzbQ$np0`geo5}{q3HEAQ!oz$ZKB( zyLZgF64h1h<*x76je>5i9mo3{r&OPm400XK*8oT^2~FN}O;t#o3BY69QgPQ3|2cGE$eAf+gzK*^|?I?K55L7b12h48A_ z|9x)a62wft$@9XX>Y~K5Rm7lcVJM2<6$fKr$h2K!)ns!@M$sh>8q(g9<7sRwWRj1U zKc!&FlxZ!dq8Tt;_T7!kCi5PcM%KaY;uJZ|Xc(ryMnTCFhj^Nh`zTlYQTL)cHu?Jn zD8J}ay||begk~Da4+|syzW2{&@b-bn8@Apq_0jIDxNb+2vkW(vbwZe_oRvAt2Iq|_ zpvIXcV@&6ID8M|46ksrqV`F9GDU;1*D9>or0NjL74^3iK-ND)v7LH>oJ}f<9b1dl7 z3)X(zNneo2l8P0E#r7IQ+e&khFnC`*A?#z_GIt$%N3(*Kob|RVuKnkaCMwWwON*8{ z;p=Fz$v;Qe6Z8Yy)>_8~mx!hb*qynu9bU(?xKJ@|ll0U}8wV8o=*vaS(^-nCwU#Zd z!6$8+LmCu8!0BzWgAjFeuxJm8>3LcBh^&27g9pC^e$3X#3D?zb^9?~E3(M~xT2`aSG*-F&(NLI0%!164K zRkDudI!tG6Z?rB`sPs|gW2JmGJwN}bD{M9KOs?a<2mgt6^}oXO9TG8@?A3?WMTc#N zC20J)fb6cvEV)U^7<<__>=ddn2g?+;u(s&}r~h+#+Z_z*#)%ft^ifHB=rx2Gds>*& zgDxZd>3!muF^|$+lqm)K0d{UZ2YUd^a??F8rohK;X^*~Wro^wPwn?=kR*d^M`H`~i zOD1;=_*=2~Q2d@8{{_j_U!8epj@Re-oCRgVy(sU|5mq0SqG&ZEiqZ|`ynJJ{#Hs@i(8>+{1(o4qG0MM#CK7$4jD z3^A&r0ne8s`Xssh1uzC>l=U_EuJmr@(=NV*uOH8wB9!jIqMte_MFTLnU^l(G@89X0 z=z0;EKboFVZ^yw}_hZUYvFdmFtb$Yiuzb844$sK+gDL?|@_s~T!^_b!0BLTR`Ngj$ zt4EpB$3L&bN=8wGArt27wMZ@o(qf%An_a!ph*%@nD1o$4DHn5_{K)H?G%z&>&`@kzUuBo^5g2Meiz$r&{zI=32%^iB}E!P zI1Wi|7B@9Ul+vR!4H>TvV1+fI6?O0Ws?oV)5*@gB+f@lUrp#&Y25&#`kpq(}|j zsJBU5cThj3n{+>G-XAMtB$woP7d<0eG-rXm+B|E|!ru|gs_7X^hahXdRpo90&-m6! z+8t2r;d#Oe;J-4K2ObkjMvCh(x( z_9bdic@eksg|SpL(-93EZe0;E$Y^YlgBrxcoRI)D7??s}cY|Lg4Ss&HV{ypTr@@ zOkwlj{(>-}lCcCAt$7VtY>P9d-c`g959OUIk^;`r{99`v>y4Q43(mR9s`y`d2$uhw zhhU>;{0{-afX~3h#`J%92v&Ly`u~0XKk^VRph`$qpKK%yoJH~C)W=V+f#3;nYDDp+cfBB1uiIZqag!vVI7Ej%GUw^xHU1wgivm3WnbyvN=eO@ts zoei1fl}($Fw4kB~A_Ru|9{8OF6*2J9sR_WqB7xuDrxDa--*hzqesS1G!2LzWf9X0o z!C;3EoH6C7cc$T^fiB)XfCv!z!d0HAi*mL_t8P1BY-dk>TT?ZdkCQ~AejXR;q9#U z_!J<>+w|*o9`NIOdwbE5&xt}t+9)9-0KO5_*zzd0z+>(Mxqy9Rp_l^*_kF>TfbW2( zx8Zqx%ctjP)qKgpV27x<5$M?`!14AX9YPHK-ZuD|w1M}m>DVvmOaptdh5USVVc-eD z-d#KX(GX+;c|Rb6`t-~TP!WHG^0fSEA!OO_T2lPcSplekf(o*HxdeE;=ic1P@R0W* zod>wS%(4G0DX;(v+&_NvWWzxR-VJ<&z2kHH%0hf(gZYkUkefO)BSMPmdjs@-F7oT` z(SKEg2mDkm0|&o|?*DLh;>*p@_KMoQJOioc!SD3gX-D_++)?)VI@Q=w%l&}{n;i4^ zx3k6P1~>ux$ll_fgZdeTc&{FL#S3^8@C4MpBkB``r?vZn12_eK4g{`8*L8!q@x}U~ z0K|vSV*&~R4ba;%>>BC!g*6ZTnTH z6`R!1TwD`)`**UIm*)ffvCG?IQ) zPOdIK#wzc%zW>$<#6!&X^^4udBy))FAodcW6KG* zd;EMNBJgU20kkzT06{r^LQ(pj)A%4wA^8Vj6?((>;vwgegFye#VdW^(!+jO*2aX=% zAz{mA_@*og_0P@pu9MJ`zyul4&+!BJ47-W{2@BjaKZAyQ3)I6GgAN`!5cGSy7x1Gs zgWh}PB{}xP|7v{Fd>0*A1=RnZ_dW7O4tO`9cgy$&1nP!gAh`F!TFoBFXC}E)KDP=Y~51?}-JY^8AIRDOe%1vbfg;h3bqqED5 zwjDFbP>{};4VcAIkP=nR1XLuNx(&&-u2^}plede=sH_6jbpziGzr(j7wpu)#eSJwT zW}r3Vez{$NEjuqy`-cDbOVEZF1&!Q?u7g6e0^tB_p>uX$|HVZ}67_BL5AEWAt@Dztlo!O(du_U344o)p=( zhJ*G3d(GVh_VC$j5SNYoL`h`EKmK9J>#7spL#wM=XudYh@~qH#LQRI1CX6}N+F?o| z%I*l_)z!IyaE~7YXD)V$S}4%YweA};x#MMcz3yJl;+(Wvv9Fw+1qb`n%r`t!ff#%? z#TYi%z%5Y~m-F}*Hb@pUn1gKjJhb>nEU@`NL%{x8IhSD%G2DJWZODa)%Chqu!HyMS zIo`(C-mt8Q@!k5JVxI#1bDU66pP~e?5#Jj7YH+O&41}+nKUg%m-K}BdFWfd^MKv7c zp?p7gm3*i!(PSvaUP_G2`WTs%X_*-e_kNl6+1_E1Z9#5^k?h^8yTlY_ z%5e?@XRCKVXX0%P%h}n>j3?zsE_6Yn5`l%EH$yuShMq3gp(e$__!(ZOn$^d+#hn@P zlYueoFCpZIK94~Z3ndA$a^OANwN7+ppWZB4=>?_42~uORjLU0QQ(8dYB;~9QlR%tk z5*etcqR}$QKF1{dCG5PkC~7nwMU!<==O%2F_l{Y%K~cegB{nlP8GJp+)NtJsrIUP4 z=iPT>YN@RvOK}9wZig~{qwvzE{Ie+&TbuXm*dm$kJm#%;+h~$Z5jGV}%a4M1V#ntj zZi(|Ui9XVfQhIKc*PyR}*8Qydrhnnk*qeP1CkUqAiZ$SCLc8aJ`R#w&W-t(cuOnX) zGuvp#N?lM+38LrtsiZ7BM3${Hj~J(Y>i3UkBQnc@zFv%J@b9^+ zDQDKXatq*FemCgPOEn%*{Z_EwigEh1_ea~Ct(9xB@+6ji2Op$&m>PN(A&dPmo@XLj zq|4^@-{iBRB4F zi~rSRnGx>@&)pp!rdiqmXq|8j7u>u$Wn&j!_hJyBG6zcXk6t6)7KvgHc3UH7-RypQ z$N4^GalS%{4|D^-C#G0jT^P0xh2lq)YqmH5J8@+?2wn!*VuBP%SP$zxsOOXU&52CQ zR6dxxaW7q*_{bF7;uUtI|KQOyPx7;w!MYEmwQXh;G?SdwX7M+3tpJ$BGc=IxfAb= zqa}66?;{79O_D0Lzj$q)82;KgZ*hjHl=shQ$A*z{2v6$%5b$Io7pG!BuD4 zahs~(`KSa{a?@4<+gP(_62ovy|H8U4bL=NH$o@|@NfkwIXTwqu!=c4^-ShgESNJE6 zkKff)@TG0eWT1VI6_}r;b}&)J>X^y4pxq8)%8LcaFwI{FIZTHoUd*#*>}uYVjzqP*L6vwQQGamW_GZ`0X^}mela_N0-tT|AvT& zP)Y0ig6D>1C&shAY!pBZgkmKB2wYwCytrKvwSj zN_?BiOl{4kW#TZ?%6S4L_Xf9jy2pN8*ra|yasRJlJ%)%juX6 zE=mAb7F^W`<10N;=krE2mQf8C2ypVlD?&tV51G|lugVOu>MY09c3@|}m)2kQBZT35 zn^^0{s$_>Skt`ih?D1Mh&h443?oaJFAJNlc%?5jAssfDZ>650L$%S0h8uvfA%{#>) zU{=~J7Ri>0x4~Pvu`KhQ^HLY2TSW(*3l)q+vB*e~VD6?5s&4K;%L9M0ms)6bRlT3} zRv9(To*q?RbJ~hYK0wz9!WW9lT2_PI=($EQo~u>nTkJ`!z)e-N)4Rhc6^^W`ecD5>4KeAJI9uQD8tAMR$j>^AgxcxmZR*xIp-@_I6 ziV9ZBb++pQ8zY6Nv;}yGVVlmj$CJavOs}#!E!G* z*4g=VX8~7N3N%-#6Zk2fs-wDDxaNFg-veTDB=}-o-adTxL15Y} z3>6R3);42_6{RXC{3j(?3i+vy&is>#HS%~6w8a977v9p`=B}M?SrQf&=x;B|3P50U zwD!Jr(YJr*erC74iY0h0jT|>ag^N`CmRBf^$)vrF6-tk>oSxaYQ;H}ENk-uORab~~ z3q_Z9z1AZRR8Ul{RJr7LC_Fa%4KXEkVb1KF&(I*NxjxTnN-&^>^7)`mGbDEf$Tf$# zyyK!i9N+`KA!n_Bg{LH#c^%bl>7gOFyW%bOteDUp@Nuo*i86Jp6dRZ+B& z+=41Y-1!YT-Bv}~O+Is`x``#naQC4o2`peh4~@tCI=98QfQ;jGs1EHte$Ww9x-HskF^Q0R;%VK4h-nB0fkTj4IYei)N7> zVCPPm%H?wzY$nV1d0GQwpZBA{@~oo2s+}fc`M5(vbH5eUW5v65+%z(|;=qmel8}A9lSLU4Y+SOb)KQG@Yd9 zGq^!tDaTa2-SIE77I=1CNV!Ewk{)&g8#j*2KID-v-mqWjs|0~*T+7E8*!l2A#Hwwb zUu4%@sYu=gZflS(^6Yk#y=X?e*cuJF7wR?*U-5v0jL}!GWSTRwNh+fi@6Kdnt~a~U z)kgX3ODhYSnoE9OelOovZn^K=3z1M$k353h*8d4r-G)fDQ`zukreOpjA4%WdI@SEqltaZ0=O<4 zY2BP>2<^cQ9ZG;D*lO%bfj8IBRLt}oRqlxPs^FadvFK3%lrglljqVj-RJ! zHu-#g$#7T>6ypI*$6G%hKKzt{3X=pXFt#-=(c@Xb2xH;HnbVO4%@nFC)X+eg{xyL!ZnyS}v%@PpzT#Mi zd8m1E8A0uL{`@nUa~C?Iqp_H4#_UlfR6@GvY{6`gJkUS-!z5^tEd#V8KXkk*pt!52 zcTX5g7j=v^2>H)>ToDfec2Vl8zyU6K(0W&S=o~j6yG(0h`J|SJ^;WN#u4SQoQDO|& zMo_TMp|jWD09GffIc+ufqH5e(uuJthY36HWyL>V)LC}0<9f{uxVkwhq*^zvkL8sha z!s$@)xy!@5*>=C~Ldon+YRr<{ts9Iigkh4QsRg>^R4U*mp&p#_sTDH5^Xms>?E|)Vl;NB=c8MqaG(N`&G+wMTt87$`vreu8duucVQSQ9p*90(8Y=3U&`qVUci>-I*X_}HZB6;TSwA-t(2*3(az9vv0BQZ7Q1=fS9l#nq zV~QCzTLCCpQZ97Cd_0E2H7}{>ib*UVtuLfq@nT9%c50Lt&|>mVkXJIk2}H(gf89Ip z9ukkCX{M)EIV3Zwl+JtTWso`s8X*^nOA?NpA5G)7Hcb2IBs$Zg%L=ceuHS+*HHcQ5 z$RvAryUdOge76;Kj=Y>B*C|cVQK~*)=4|S!$osIGX8sVwa@aonO+vrta5oO}eX3Bc zv*QGLd?`)(=e)YfUfR0)mNJ`uxHH}j6FcYsE6?`$IVSU%kl8T(t#dy6<;Qzoj2{5e zZX>L)428(?aG#lYA;XH#*q)$kUxwv{%aaU0!jU^a^t^O74A5V0`J^M|JQsf1vU$Bl zWK$g!4IY?of=+rsr#iocjNHT87*b8_b5V=)$Jc+VaGq$YAO*3_GZiE9*g1j+C-Fzr zfC!S8C%YuF07I+ZKkg;|qMeTR4{$(&Pw|ZL*0`fJjz$sWV!EcMYwN29PAMQ1B9hPb zC}eAa9fl@$RsKIWD#9UOslH=oU==5BO{Ds+Dav2qNX#WOGHk$I7(7pc(4xd>%sJpz z^-a2|PA}>)ELIy41f$k5iwn2iG7HH{idFm9rvP-?{g>5rnnHk`5WN#j%Ew&SE9^?$}T@9ohas2#N&&4!a0XED|7tyrNXH2(_p5XpGm(* zOM@rV#XtqiB)q!F;IaO6npuBm-AG3C6p9{6Myc6(sN4o?NM-?MWmXxE`HTc6YnII!7!%I zVf8Z|4wbPAO(J)4#WPpkPs^owTjnZMO^+^G05Jtu=dk%G z{QKL9?d?fkT46t7-_wi<;Sys?+q+gHy2MDjw71>vPF4uJ#me zY}~)DVZA{KcvEgvC+^BBOf0Q5&T&wyhZk2PNX3Nv++Vmw_Tm$9&#_?XhSi%k7N}Uj z6*fxsehZma+p0!?8h2n)n7ioQwbHC$$@|T6^VMkMc}A7sGu5f-$1ezE$d?E!U#J&n zMi4-u{fcNai>5^vDatPj;x{1+W?lV6r&vX#S+8>(Kj`sSPrCB6C zWYmkyNvRc`u_(Fa=RuMH~_fK)!E9MyU{_?I>xU(Ovhq8(4 zbKq(;Z|59JQ%ozuTPdiXw&61b+ACUPMr-VznZqpcRk)<>j(+YQ&=D}mCP4=9{0h*#IefOVvEV*vg&}da+MjK#~Kj&voi?GJF>U+AdMXvr5-`rd7{5oLgmiB)P$lo zL2=Z0cB!EerR}JJUa+&_(_2%RebUjt3G{m=sqSqz8IMh^q>tAn6yb&8Jy%pVn}^-m z=}&fOb({J>RC;X!%f-}+{oWUSW#z5_?Q4LWts{?Qnway^FLWLRV2*KcuU5B@2y@Dn ztri^DKX=T`1ke)5hc=jMlxvIG-r{mJn|lYM$`qVDP5eWAiJD$q22#^sGen4}*$?WL zsQWJeJkU&iUcZ(_s+G8zLQd+v&)-mH`EbjrT`~z81WZVlfut;kp`G!ZDa01g+oUzL zmi(jLDl>Ah9}Pv-oq%{I;dlXJVL;s}fD}IO5EEdUbtycfaa>q@HEf_9cp5EEpSgqLbX{x75f}t+rMfh#M)DW`P)PgOJl%8G z=$RA25Jc5UJUUT-&lSQ6s27)Q?l~&nI<0R`?F)#yZjeC!} zSZMB8QtO)h*0o`gmMz)q&Mn_-n`^2B-+>+xyaG>xQVdkgoDvf6*c=n@R%}@BgmONn zco-A~?4HLqV~j21Io)aZP%;Pc+0PNoWE*1xZvp{bpg7?utO~W#y~{UB^|WddT`G?B z98%Q7jSqolHg~GuWUJuzpQ5zD>X`@u*VOSs( zGyQ)qMtoK#HrD^oqR;8y@cH(ImO?DTX?zZb$w@rWsZ?Q*z7L*hXbwLB9|s6gVPPA8 z8y_ZunKB?KsmSSTl>PL}_jITEM!Ru^ZFlE${d4Zi=w9o=lFZLD!NA4-De{Q zFtHC3$iIJ61`XE+vjpSEiJezl0XXO4Kk)0v@&n)o;Cl-OZ~*+>xwU(x8?1M?JFW)- zvVR2>^4YiN0-%|Ogq&Ah)gSsK@&M3hm#NENm&gT_4EF*unANvJ-gi6G4`9rp4S>$F zw|l=uU_*~q#Ffi6b-o(*)jN@AqYi0P=x65=G7x{`*88Ct)c%*C%<^^rw^3b`eE{m_ zb+sA@5CVOoF( z9)6c{PQWyO8y2SAf<1z90~WM_0|EGc|9qRo6r{oc-5fpQz1@C4RATTjE;AneFx~eW zK0H9!`r*+*^iknMgZS|m;QNtZknH6uJN4D|Y6JWxR{Uud2H@}G+b*a%*TwPtApscG zwYLNMQI~@9H=sf8yT?n&1Pu0vUjlymm44o(_+<{`oO$G(|QH3t13nRMt+>bdp&V^sYAz?kb zW%+5yC+GNXgd<@G(SMY51sWg(sLRA!1BYw&NFss01I`Dr0Dk_NwgTY8!}b>{29RR{ z2e3l0aqC@y2Kod1rr+!3D}@aDw%3eCq)>`D8#urGlyqWxaTDRzW*6mzRgcwxK>R$f^m4Sp|uwSZ`X(KFafpYKe{%j&*^t`v!)<4U}W=N)za4T%H>;R@w-m0r6MdhAxl{42?K98)72 z36_iAg>ct0^~gQ7mSDNm5Hc^#Lk#;p?_zk(9aRn+^<-D~p?gy(>8~iAZos!8-Z^ah zl7g(zz~GS#q46bf!LdWW)s|B=Am6eiGeqARUqM90V;V`6|ZCCd%#a!03); zvL8GY7Lixarn}_`g>#)3-$Jj_og9LsfZ6a_L&s{Q@jQzn*(T1yT4Q@UhDy?Og_4$u zXzBIuplaVWQ}@l(h3LOTK3MzW-}g(9rp3Cg$*bWtH9+g3lZ1e%S?o~x3aAcU9v#Dk zw-$SOXa#9uIA(z-#D2?p>TVj zr?n#$tyQGKk!KS@rG4@6IX#h-dJe@JXF_sD-~wlqa*yfRiBFDZJD|+L- zGM(_+%k#aJuW=0m8ijNS=&d1&=i}SsrQNhnCS;2Ro#xQv^1o?S%8t2hvm+L74vzpj z32ozm$*@;-!&niRPE$Aj@~;F(-R^ABlBi{-Yq@(U123SSpq0F{CPtko~Wx4v8F~%Ij@Z-xv#^_S$dd0uj8$!jK z>57g~B$r#LBajcCWfoLkPYciG6~*;&B$4(V*pj9rk-A`Td^vJ4?^t*G9sAYJb4okr&Cy+wp5j=>n%RaN$xdX+9y?&gKn)( zz;z6ZvY<1_?}Y9e<3DFW40!94WKv^S@2|!~82PLV=)EqtWBfnl~{9 z#h9dtf+3X476uB63;&2C}%a52oApj3{s2s%LX<9ndZtxA6m+UJ?SPjn)xdR6+jJM>cl*?hnD%JO6?9Gx&yNn*O4wgk_mpg zt}V^)6%nOG53VkgK-E`TC-pz^M8mm$W??j)JX6^bXGGN(dz2CrhLgafLFRE8#4}}- z+tTV^J@A2U3ddD*$m3P_uvat<&9}myvYb?&UqY;4N|0d=I$T%-4XYT zbf*>z5V1C^WDOm4oG(JCU;$uuenH-kccVdBVie_doDzD9CYv4z5^$giq9=O(J3=WRW-A{3VBA&uE zv7Q%Fa<(bjW)sXpMa$GW_u_y^4$MjFzi@loyvAWzM@lMy8DwP|jvJpTlie)Xjv#f) zM&t^d6{xiO$GV=RX;v>5&}vz1m0g1fV&j?>bL+toCSD{-v5sk}ol6#Z=L~=L7s0#Z zuoq6D<81i1_>nof62FE640Zz8=-_yTOy*{CVMZQIT*B?>*Q{ZB$M8(w!h5hek%Q1f zUPaZORC)ULMH`MrvM|cBFzODX>~~@J#p{V7`<5CGG~E{G4~FTZnc+|mR+j%YGcJgt(0`Zv)v z<6Riwcuh}v<1yFJ6mjfmS7%9JOT-XU{#x z{YX`v9oMU!cQK41ICEk&)+NYWR7K80%(7MKwh+G4nGol^P((WYl1w4M`?g1$%zN}~b;R%- zxbMfWKb*&6Dm-|^`dKdh%pXTudf55Rp(T@zq@|+cLx$*k#Ok7W0aNsyz({Yu?$@`_ zV>#Xf_KiPsPft?Sc)ck3(W)=_2Zlw)@32-69W|4PtInIQnZP&{-==nBkr{iRe1?^q z%uPX5g@T&ilo9{Lg$1?EoVEe*K%rnrY-9?G$sU@(t({%ZaWrCe`%Uv(vQnD5ah&|c zl`WH~^E!%Z;&~Bo!OC*zDAUC1RPd7*#on%9S-F_ue8kJR`3GNe`F0{(FMpAo@YQEI zFu#dzk4hyhW{3!u+A8!Eic-r0P>+HY=&O2#c|ft@`7w7LF?aI6H0zYC&gyHI0&JN9{SSv+YnAQKZYjnhRIsQCo@l z3jQzL*zg%vzg|IgAB~IxoG-YmX7SQ~5`P>HFc^&$n(Fq)!;^q#C zSyuAnsCT0C<`ba!UU^0ASznrSCv0VntF>}TW6X*suPewv<8pFn-L@%ShtS%pW~ zmC7L)r!EIgEznV#h!}Tpffq-xCZLiXg!#Gt^aywDiK!e}s5^!&2_ zebu~h^5-?s!XH7%u=HD$9j$VsE4NMGO2#z~PH&7orG4W*bFQ;Vi33@Ydmr!;yjek) zE=Q`W;cX7ih%U)a)ZT$u&$AO~*|!GF`bFFKgMKrnD$FfVN;Znl%CKWJ7J7dbTB0hg zo$p||2;YihIami{KS#)~kNoY~zQ()`osG`Pfg` zoH;Nkc{fdJzuK#GpJav_R#OJ*BfD94luVJ$^>kSILkk8JcGjJ3o}VIaz|@-cGs5=% zu^eTk<7p;{XL&W5R!>A1oi2lQCiBvgSX&o?j2nMMTXaO%yfFgvlN7i3ij%wge4VL@ z$=Mo8eRDf3a{0DIvPO4<4VNgfA$!Nqyfykp0xhj<)Zz+~{#i0owO+_*LDFldHtq}6 zjSNN)Dhrd&_d+_P*kG51)rfl3pNAs{j zOpvYS**8V8GT5_6LV)eSA{+vhs~KVG%mf;!C;hith!~7!jt**R|4PYwP}-=@6--pG zv8UJ}wy*0z-iuQ_xThiC$KYUn&OyWKD+(h8wSy`)1l{UC(bd{AF7tajY%UiIzbW^7 zcZ$}B?%Vek-fl~V8H|~6TS%DXdjO|^VW46j)91dgR^BIW_MUYT*vpZ9)z*Q-D`%74MG z$N`{=Lv$J44;q|ScGsT<-7N_PY>&H#x|r_SkrKNC;{{7JzwM{^?B9UYGMyM2XQfB7jgk*hcJDVzK=1$9r6EW z>a8U+;8VC$)A5)pxtPuKkw+56vH6H@PlgULtr~*@Nu9QmO(Wzl%o8#Si$Qt|x; zO~O`L6;PUx4UosS1yFZc9Jr`_2#5~W&`#c8eTHr@WrpLw4n1a?CjR3@_3ms>)}B2@ zR!%&57G54UJY0+%0pl7$f>bZ8eIsEoE&`oWgA>D)S|TZ5{^qhTExkw&lPd30a8W3lKwSKf!Fo8 z;`6eYfj4-VSe@U(P(sf|iau>OLeSsn!m##c*xQ#R#^Fh}plWQde&79GOLW!n&ORFb zYFT7UbKY=V3$42p2Z+b(s^oN47=rA@34#OY#^CKkfN1ZJ+!Ss@T?1$e?8-g_JvQ34 ztkmTK>}z1x^SSQP{&mGE*GIhH=w;{{$d=8_h|<)h=phc)40w217gwE1YL6Af8Y1BC zcri<^TXEr_p|_9prI|Rq71-IpkcYw5-X3F9l1=g$Tay&@zh!Wqjp1|9unJx|uAHRC z?Promu;xy>;ZUB>A0depkAnKqMa1tLkmd!wd(!1H5V?bmAJ2+$yRlTu)Bxk+RZvXY zgbYHMC5>g##uf2W2Kx$7)l+o6jRdzm>U5WbM9eWGQ^U(8hLm=#P9#j#4tMKs;jYN zr(@f;?WAMdwr$&Xa{Elqot(ixtfwY5tg7|yy-eo!q(s-J$lNg(;t(rx`V#pGUQNeQ~Qt}b_>>-h>^Oiu=J-FSk(DtKLl8iGRpDwKAl;xen-($f!R|Vy%pLzqcHI|*g5@}@N*lv2Qt-(n6Y7$f zSKUj~Hx?0m-j`_8itH?vm)zIvd6yW{Qe*_Pc5`ND)l{BRqLc?u!)b)J)N&1)a9z$MnFnuCRK%2)#^UBj#GfjCoamRTI`*rlCxbrZ;$-)NWVz zf|ZR;2Z+>K$+t;qXHQVoi)`w$0dFn-)G$KxbtvZ%_Q=XYGYTUXicYLI;;ziokp)hv zuD;t*{j6FE_~vBVsvwc8RB`YtN*1pJtkO*`WJh!k8U>Sz-e)^IT?d&El{P7s^ku$- zvLpY}w4-vr%n)tcaLeGG7N_z~$flEQ+dXlXed;E8)t$}E11&Niw(RD+@~ct;Cx2&z zvoZCUv$G>+iYA?rL<39XozEqZOgk+n*afnDv#)Pug~)n&>1njO8@^$9#ZkmD)_rDY z5{P{Pm(pOk9V{Ig2W*zgd*g6ML5mlOvt1;rF~dV{s#`jcw3`e^=CX2DqoGr>Kjt9D zhe;rMXEAAYi|5yZdr~d$l*^0X-$fMqbIj%440L6*4&68%z#(e-Gh-WB!|mjyg*)Nk zr%z})gA3}gPxndz<8$*3KcBWV)cSqjxSRQOGl`60LdqNsn@ci^@T6~P_q=Q3hn9F6 ziQbe1F}+Rq4gF#g*otReIZwBWR^+BKasxv&VWPOE@-}3k}nnqS=`w&LB0aH=cwAAf-Y5 z7>c}j#QpZ;GYau(xQpW3G%ljFxZa0=+;BTaxQ$|S`hg?=F1s;(h>3RBzJSwtW#;5= zT%tbzS!CFqi@Y1E7y(za!C6%*(VAIqhkcumm5zrFq3dA@Z-)!uATS$%Mj#)`pzb?! z7b;dKULgWW7G4%PbCzu|+q_(^&)8gTBxbT53+w47MI$RK zH^w*aqi|=$`PcrYQCXOL@(oL2tUtbJ37y3v;{EhpJ?=!H5OM9~o8hBhDEG3pBef)!AqMRO*P$Ul$U9ew)7lk}qGoZ$%+Pzr_M#E{_>0*izSg|32egqn*KJ4IQJ z+YjGAnma9~Rc6=TR}MGcH&(W^E+9q%q-I6Ls8PasU;={tSbh=JNRW^KV3A-yek4U& zS`8f0FuFn^asn{r$Z5Jg%A4z}l%o*1A8g#bW8L-YG~0x$0nNTe@| z5Ymqp^a}i`cl#97A0#SXmY#xhSMQhG(dMkV9F~CrA0OYZu+SDnk1{uV$~ z-j-q<;~e%?gPtE@ALvUb9q~6t?;zaq7Y>_fd)^n}zg}pVUISVAAhzWJh&|YUz0j#3 zQ7q1Y_Z;~_Tchk9a9}?^TMz)0|2O>0$cGsr=6)*E;26}|9+UuRFJd(S0}~f|7UBXj z|7#8y0NMXm`U~_rdhlJy>lZ!yAd=NBl_Mme(iqZDALdgjrv(N2IQ$v?KBUh#h2oP5 z_BnY8ahg&b0f7SeO6Hx3PX!bDJjnYQu(y-l70CboE8rWFmOiLqVumQon>$zriJp$& zZ^=0U3bpV%!ZEZ6$e=%eUQr_j;2g~FovRJ%2i6vO7wW4R^ed8Q zJqE>dEb}PNJ`7l%0`F{G-jDL977>^~;2(Nq?nOF>7K-~u!GjUf@tIgXF4X@9SP`ap z5&~{dZf+83Qgo-qLAiGc9`wG@ngLW)nSXD8s$Xrh>;Kss5lJY(K_Mf;K!EacNfHO~ z1;6oz0l*)L!@jSUMA~tHvz;}=+_Rb}?;k|Jml?ZTpl>`Wgm9C8aP$LV%*Jn@pZpTy z(YNHCF7=0Cz*qEbNBnyS%HMnUR?l)<@BK#%?#{0dmH~=)xFf%H75J-UVlA2TK z%QqgAkUEIJppF(`?fwgZK@#z3CRQu}Fc3o>JcCE=_|l%`OYX6s>$%&(`;_|S@9gLC zrjPT4K|}_JIDFmWYfQ+$iqfHs_ybJ={vP8{Jj-bp69E^FyC;R-Hu7jS*o8cfAPOXBZacr8N z01QP2#kyZgwCx_xaTt>$Y&L*;u;s7o=WkI2c(K2^@VfODqz{Q9)?^Xr5E?WQ-0WB| zS)PB0_P53d$Bc(Y1AO_n*e3CcI&(^f=#i8)xj+8Q_Xt#{UHxw3f3GAgo^2ObMVq9+ zS6ETF+F)A()*SPM4cl+~jxi-|YOjo0#vjU;Q+pcb%>mb;@qiew-`+3aUU4#CKHksq zG17cLn2_qFXe-_jRrl7KjaAci?7G>3!XGMP!+%-s()$C$K&No3*t&NP(O!IPipR!9 zoH&#q8z%5_(3By>V(}ZS#G61W8%eO>D1gW%SuR~5H^Psf>UTf|Z_!@SIn?zjH7Ax2;Yri=qn_OmECz=! zGG7op>}yYzWO?=`cX0;#E_AoGOk2MMXuP%8joJ52^@?Q0gvWkOToQz&as=+8v632Q zKLIrEf?&Pe7}-7s9n_D%`)#&^T47RK-`$n?iq#g_${R#?1Ta`V-yxH1buG}r=Eo7N zEddeZZuKY55pNcBBT9~2d|<~EIrTi1JvwJLN=$N|gcv$L8zoD~sg43FdpT!n3HeJ* z;UjWd`sy%<5A~-4hpT^KbHZVyrg^ z?Wj3&P#5T}*WZtlYGc#mZq{4MmNuPvX}_905us7`f+DW2^1dUI%1<2=FwkSP3Cx-7 zri-0@x1Z=v>haIQG>;+4?=h3M` z*(y!xJ@H2H4kSUxB#7R?bp_nY%XN7$aR{gXA=u*^XLvI&qhYR?dTmOrk?|Aw>T*Fm z%!x>@_xQu~n@Xw|_NIy5CMOLZ$$K|U!=pH;1c;pcb0l@)o2EMVTzj`kT5PArfUZ$-v?Low1nCf#jMQJodponEhs z?^pb10fJ`v&%_?&yu%2AVp6PJ)pB!ao6sf`2;f{jKm3U4)~_t3)vWf%92aYU7tPS% zq%R0!5Gc_zBVQY;q}=N+*nKOtyJI$6JAfHcWKR{ktJJ@~oFehk=1tRMVY&A zvNIs+y@$mLQJj$W2RwY&jD6AZ7%FY&{v*ZndRVqEw?&n=&)IAiIc;az-Pj14bEV+g zp1}Ppch1-kdBj0WyjDlod$U`g=W}K1X1wT1ed@}43>TwdSssFJ7mL3f4GUK) zQq5E}Tk!_uIj)7FJqh5v^>eWA>NJbhh=8cuno@HqoSw_Vmbq$V&uAQYa`#xn;z|QT zk>lkD7|4%suQczIC{Q9*3rEd&9S0 z(@X<#^Pf!d0`};Ci~`J}o|i$;O<(?Ew!ie?9IM1zXi4_QL zDau_ad7ru_79iuk?g>l|ipdWY-jR5UV1Pp@m_~zvgx%N?CR*@ie?^vlHQrQ?3skny zQ*DJWsvtPOb>Q&~7#as2(|eQbp@kGYUYMHJC%(yiy@*!FE2*8soSo42gJu*JjgM#$ zvvC;~=;UrUw{`s;1=8hS0w>5kL`yZR)Av8SPLi++_9+0%@le1*&2l%Pwa=^YDfON`>r=ULtabT&~$lTp)YvG?>*Z z`r(%dzw5Gw&FvP&QF1C^#G<+oFGKu(n$t)-2&Wl_e_brpZ8ZOG57TI#vXIP8M zR`6-Ayr2$DRNA3y3bDSy9nzBTk=Fl>>os!^*|*ctbr2(BuYOpjMWViySpJ$J=z(}0 zb^GQX+8(@650nG33RVq9HmK(*Z{y(K^CKW7sJvyUUF9X(^+- za?^NC7y4OK%6R!Y#%t+aYGaclu=G@t4$Nbm(du-!u}=8 z2^eNkp<4YHe_O?xi?PNloE6_KD@z_}VpPV>o6XV`c0{YzE-`7*Oud(IacIdpYJ($m zs8(h2t~zYM|d})g(-L$9oK7N&-L1 zcY2%pV6ge<_~Hp#0{*UwVr!X*+4dy3By2FpLkmm*86FE;Q&C>s55&w03!W6J(zX55 zPz{WQXdD@nGgrM0E|U_w(gDk(I)N4@<&bB$_LE7X)xww)3oUvn) z$3>sF$d+I;)-B3Wd+&X@kaj}^-CZa%`0sD?B@>>^kc-;xSMa5xw2=sYkp)v-RJD)N zrJ8tnEGb{01T`8+l+DexDBsY;Uv_`uIx8kY02y{4oTHoU^o&A!ryS;dGHHY+ai(X#MJUZZ~$ z4Y_@nkwsK#XIRlP&e6k{rmexJt^L1?dQa-x0v5Ek(1eznPr|vJ%FA^*LaG7Neo}LC z-ch&fIgc-zqu8wCrJV`Q6`rZtUD&a02arO`a9$j-h1h5=0K5sqTjY3s4S!Rhg%4}R13=8KG_fCDqi&C~&c`t`BaQ?xR>YG7wjaI+_LbUg*_AmBWTaBZx zU>4Yi(+a3J0GGmje>E4mt4(SPHqbSlKe#k@ug{7ZZP!(Sdszh@H?ieJ)d~8s#y%^T z@A!P2byHFK-pzg-w{R<^cGX;xX=^&0#PFOY;Z5B`v(rxz(s9ie?5i(9i7BW9cg@%& zHBcI71O7_~EEYk=4S{PvV7gX`O}yTOP$qAP0BNq7vWB-;I^}Fg_qg**I?@hzu?w@O zhvX8Os68&F>26Qsg)!7a16ySXJ2tZV^SzIG0Z_T~GJ zOLWSWn|HL-{`NP7^)q?Rfys)I75KAYBA><5$FW`oR7-Z3#5jjDm=ME2;eH7sZO$(Y zlS#Mfd((@7$Y!0PMd)GNe|0SnY6by~Sd#g&_6&Nv;*OhY?VX+o;qvUxq-yxlS9i zJ%KlIN-s24YY(rFmcdDKz0~BEbT)r}>JZAL!V=XWdfc>nb)FwMHtMn#E=H;{SERux z?X+gyy(;LjqPsfLzfPyIwk19P`n+PG*J?}zuOK3IeLCho4ao{Pr+Z3uWc$ar&1qn( zvT7s9w0Mzg*{hF*0;gVKV(?LrgWCn4rF)h8(s*Rn%^Mmi~5x#S8fP}Wt8r?wdp*`?4WY*Mnx+yCU@_aAN944Pejnh z(lxo%R4jTAUM)3LmFK&{i40DEx9U*>I@ zuUp~n?0Sn|M;3Vt7J1s0KQ`EJWV%2rH2mb?FGtQeKMx@!lkiKqQ6dIaTHH8&wvb=< zXdFCASapk5(BumK9Z|j@+yQIY*S3GMp82lHH~)^3EI;fCROqYSEu03EJO3S&>0arK^xahht!({ zrAf<8)%U42+nyV@A!!~N@6Q4my5DB9P&?R0rYKV7A8clrRL=8sL*SC#Rlkk*VDEAN z;5%mp1z=@OEjkZ_y{?>go#j;Mq0+2Ft)#klofDq&3_44l7P$F17!JL2(@QqNR=KG> zLP}<*KRM~RDk^Me%S~@i8Hlu;<$N9q3)~!Sk)H0Sq?a$N+j$rjf{BdUg+o(Thwf!d z#465kro$X?Y$x_7iGlyB53W6o5xm=&9p_mD=0vslCt=^%hSHmF|}D(3;G)xI-WK5UQe$m-ATY1TI=% zh)|tdMcTp)prVWaX7@BKu3t90PHmXkeu&Y4HjN>+B*BGr?keGD8Or&S9c3c~=ijkP| z(^^>S6snj#Q~u%!N)D@XZCAu@417V#Q~2Iw$i_FoPT?t6?8GvyPNU>CzAWoNRYdkslQTv_s9fBF}7!P{&f0?|Bxv`OM$9lm43IyX3`FFKo((p^;2+ERAqNY)&$f?n*mVdktUAxm)(f z*ZWu5$+nM>hE|b~3f7eaKjmZ01>;V#oD_chc3=Wq%)Y2*xNv&cjqU0OE zxP_iUA@~ItWPu8Q)}%|`ckFVZx*{XzrjV+OitGut|Vx1xrzZvY{@7VQT zRa$wSdNl|Rl$fTgQGL~AJZRl!FM;?~~{xZx2MM(-VEnMw(snjGUe#mjc)e)!8_ErD81 zrOKRwhdo)Vo+&II`%}|t8OSqG#!_c#f&4nF!RE% z7a6%Ssbd~&DKUlCNby7$ZSYBWf^VpJQ}m%zn!KN937ii zs`TRnKZSIT#oFaNC$FVF%S)hzK5- z@4MgDSiE<9;Lxb}{}V~G|1TuX^xu%~e=%#l!BtTp&g}_&4+QaoG76 zz>gs91#%&q{ed2l^eI4(9%2!-5pWeK)FcRJC;kDdVX)tRcCK-I#~^M33NZj4NaX!% zs5+2ON~}DS1K>BM3;-`zZ!c2Br&NAyt(f~-s}R5(01hU!E8Z9hvH7oXoIe+SR&4=b z-XXZ_i)Hm`(hKprfa{m%x7*YIb@z=13H@_r4FXQAt!=Z*E8hyzix2(Jww%lYD!)y^ z>j$@aoth5^8_xf+;kM3iz}jpcxKp+PNIG%`Vm*caSqugJC%IP;2O>dzuJ~swraxt+ z>bpWkqNPP-hYtUt>Is#1g~Z%)CD_f~`)4cGwd?62_53$!@~wvDf?v%q#J)HMQt*5m z3y0nR!*&c1021a$E+`-h0EFQH_TgMWzd3t*N6_xI-f%=$5O+@^?7&tFC;UM9uYR2( zc<~iQlY{y>y!e5>ewFU$B6sHz_QFGp0$KlpmuLU(DJ(Py`_g0d_`a66_2Yn);S&Iy zu3YHJp__-S{o19^_09ajXOP#OniXD%dXXFZQKY0G>;&@p6hsF2Kq(;d%gf875|WVt zL%y2f;^Ca;a(@q~{l`}<{+UeMF6Uc%`4$SI?Ta3Sb33E13CZmE3sCKg^2Hzy3M$$I z^__e6y>aw2a<8ZGtyb{kDmso&ziP{~q6hvHyFCmB{qSbwZ(0oj-368b`AFOQv$2SI zzjAIVc$tS!`%|SNw3gQ*fPd|0%G|T-4K(}JV@IKgbq-gz;9t-i<6C!3w|TqL-Ir$< z1`iDN>xpPveQ8PzQkXKwkeDlp6SIOCYSs~@ygV}gQ=1h(4RvGKZFXcnC! z4Dbm!t!fN(`ypcjPyod8W@!OV(LeytAg=G4zKC!TKh2)JorF9{fO+IKX2!Lz&lsCVQ9z1Oa&+(OWl2KfpinysHCS zcvp9sW~b}lDZYBRh+%A?QG9IC0I6V(E_f@hn)uR}eLaF<4bAH?S^BGJWC8oh&RfUD z-YLa&JEhv@iUKUjm2{d&%-rYFlQk}aJD<&Dl+Lu0jL?4ha~&1--5G*c`^_VOLA}r{ zM^r?ySWUte`8i{PdZtmPBN>jIUPz=fjBWQiMdvyHp9~3W5N*IvX%V%><6pD;HoT2A zIT?-B6otT&Sc!wtttlpM*hN^e8v0zpgK5-tLkr*6%8U^ccv|YtnX?NS3|>n4n=^ znZtYhWSE!)s!9cK;A!K2%uIAH?Bc}4(6Ysqd^}@fVj7-NG#fJ67#m?G!|dwd=xnjdt7W(1;{eQA9NC%j9pP-EoDoC|{`vJ_;&L_esmo8RO}hSt4*<2l zL3!qa-tk`z#J*QhdoI9cQ?~W9T%Qxki;%S|t<=s2(_BR1{m?$=t0C8ZhfNOq`9b>d zqF_>g?sqnde}yU?AANJ?(-4DkC*H=H#fkLRqpD3S`w(wlEuM1xr5PMmfC}?)WFrOb zqk<*{V>a_%o2zfFE%%!Mg}D!zvoFo+(!EvSa`(lI16yz?zyW!B%?@gBiE@e% z9_n96jiRtORCs4-EZlk+TQI0(4;VA%Ir`O#UgOEVJix}Wxm1S1*cpSe8lsd376z53 z3AR`4t9zHJvH;QKE;om>|6c}Qrcq?)W0aWF>Lth8Rui*hjt_RudN`c1t4G-ZcTQMU zADizfzgJl7jQ>E=d`a?edR}=OY<|XhD4qBfkASDEeq=+#RN!(Cnt+p!he74gMH~LC3Ao+NtF2ACa}ErV_7B) zT~yzK4>Z!a6`y2cVO!UPHijK|q6y%ETD0z3MFad?<&Sz&hj3-QPf$uwS*jI+^kCgz zq`~eSuP?{M;|~0_CN#@=b;^c^0Rz#VP~4R+2h^ERAb1mlhi#k68Y z2g~A6-ih1br>YcXCvMZK*SWL|5uWN6&kZFx2Ipo-F0q$uoWlrtUf=E86HHb=m8FiF2vZ{jDHXykUkqMp5doZd z+lS)wr`9(Oo`jPL>&Bv?T=s9d3@C$wF(f>?>3+w=UiG|*#Aqb&IDLBE>sR&CF*%C- zayGZ(+}*d?(WX@#%~85rHM1`sF8^6Nq~d^~Pjqvj$&#InW=e87Nby)a@;0-vIN!Q} zZnF^LS3EPr+zEgeJUb(L3Sl}Pk;XS<;AW$Ka7WL|Zir+fZqOqqAl4M3He21c8>}WE z(1;5kP&`=KCd}mM?{D{mqM}OK)Sw2xxCyWhi(yEmdO03GPbmx7c+z+%-tQ^V^-woF z6+4)S#5IYa6i@V~ybbalXI3Ao7>}yKvoV4r;G-(61?#k(B{gGDh#=cG7jt*fO5Q#7{*Wh+&qJsk{MS=F=giZwkj(G9 zd`auEyiBU1Y?kue)L=X1m?F`iJ{w9MQ!cW(% zV_8i^Atjk-kf2`vaOl2?)kghsO+G$nTCF*nZ7PB7il7Z*{UGUj%7>=@pz>1Vrs%}> z4~Z9D5Kz$#SS`UYnDDgo{K&LV37HcXbPa1qk*8Xo05$LXv+*^S+i9x-s=X_G10$K1 zP}8YV~&*OW87ujPpHsn1hw*GdT23EQ+Q zpNoHsXQ{bVzX*p&WJ97Pc>AQq%tu4b^iP~?COoN^-$?j>|0*@ZlAJ4 z5J5i&it6Y*|5&svdb#ip%(uca{U&Svm=^rTCdSt}wCI|fdpN=yK$x6L>-85oMg8eRw$6J(9Wa-SwR{fcOgkR76_GM!fF=6%cR6 zrbE;`hVITAHT_ZRVdn9hlzS`w?P!o zhkd{3>TmW#Uz)`SGJKG)7^0gjZYDW8?nEJp1Kk$weJvtV>akhAI_-cF$fXIMK81db!t}~rZXs}r|2X{aU>fkTn1qOu~vGx`#D3+*# z+^o)?Hg4Bn?Jx~kzv}gSI*5BUt+Qt}O`jxR;F5mD{h4~Y`lrlXAf%;bgi;z5>m^~v zk2ElRMSIx;7xEYQrWL&_%g*!A^>-8*3dJl9?u`KE_Fx}PZPz|RJ78?kddz&a$z(Lz zvc2p!NMw%HWt+)Bokw$mDO~j8zv0w{)|cCkyk?Q>RvX29zs;E+i6c>4u{6nvn7?U? z#LD@&UQcu(wqsxy__YR_(j`nG$MO{ue)tk2lm6XIEs?V)0w?M@xo7sTm`DPbRYF#= zGs-8aDsPl))9B$|0-lHEoLj4p?0hRNHwv4>`(!ePZ3uY*;lEZLDPKS8K+3|kBi4$FA-A-+!XpDu*xd(hh3(7&em~=yQN!ai4QIn$ndz| z@IhfFzPUuw>v9!;#B)su;ZR?}m1&Dh3C!_<(TegP9a6Lm>A}>oIthbfoEozSIR)ql ztrlpj#XMt)ke(b^ny4)L*i<33?os^vNvYbCb~w?}qGWSw@x&?68s$mZB@XzS;=q)> zysuB3JJutFg*!D&nL{Lj( zZlHJ-8_7M~$sRH6H2T=)oQ_#;*o0tQ2a_I$!|3EJ>p^Z{Tl(@A@}9vy@+uj0j1?kK ztz)A>j@sh?dX2j;NqT=U552cDg>EfjrD71yC@G)F34TXsnvwTx1HjuYz?|qb=D5M6 zZf=R^{l_J~n z-Ez##-4oVJ^led6+T5T~TyKmBTP$I8MFv21k=Zz;s5OKgmMn9VLs>7na|w&89vd+Z*X8 zV~oA`HaWq+2A8nP4&AYA2}WVyeQ+#nW;seQ$VNGNdv7$-Uu|0yd&R9oc8s~hLUh8d zYG0Q@{h75Ye%mad539}Q^>^5~4$f6XKGIj1QL5SHSU-|x1Y(seJdzRPRGu!YVajY^ z${hN-vXs08sr6R+7GbfdAZoVH*qocaliNEfJ*%Fi-#W(_YsX2STWy{wPU2rV(1IJG z!-P%P;!GMDs;jClJseBm+}l8HC$P7L)?PgLWcMn@mv%nh2kpSE$`BgjjZ$2)J?Z2= zJj`!*V1i<71>+Os$;*v!<^|p#OMz;ebvS{KUe9G#yD6cqLCyNuJkYFaHqCvZDkY~e zuvjn|2MS=1liHplf6jzP>r7U^Rz;yEId^^JFnk5%y5h2q-Pa+j=00xhRFti- zYezy%>8uv~U@dZIuNg_j=7RR}d)he$%@JJ#$n^?U?Lovv0mQ$=6vjtL2QywPmt4%~ zX*Yd;zP%P*v@is#etLp`WPmOndTp6e)3G}7BPsRAT}7jNZ{bn%=qBWZv$E=(7zwEp z%?70e50L>{Lmo`+{5Sq$Ob)M9q3(DemRdn%)`W62-!F92uk(+bq$kv)8VvY|BYA>Zf8yKgEBMB0Q8x>v0xYJSkC7AwXR*G-IE9uL&qv#k4BGKhF zRFaWqju^^gf*}&R1s1LMak4b3d!l8K@ccn`l(9=DQT$;g8|4v4Aw3}0!Ru?lwyp?U zx*JURi?<|2ccYt$aA3`SLnGV8-Tm}>Xw7QtCqRtp$i=Kjo-PC%Ow`ByB!8Ez=-SHX z%l#cCaUKo9cG1FF7CG}?X0erXB?OVWgOB z#NS*4f}Co&xFrxFeh1xEs0%5UI>l^UgV#+b!jcXWlzR$J&;|i4A`TA~vkEqO=}t8P zt*flk!*h%RUCAsAcFcoCXZfU|jrWxnYlVlK%Kij)H; zye63kE>^vmexh@x2>%E%Txa>CskXy9F-VY>btI1wjDE<%aeREc^xC$n0{^yn_v<`< zWFRc-(0t#|C?>DMbsrg6ZGp5Zv)L&JT7R3rSXNh~A1HpG0zPdpT%sXn5_5C!Fec-^ zq{y0$(u5UAY)9S`bW`k-r0CR8_pw+|OPXwT?X|z{Z(b#y<7iO^)8iAq5rYaml*tRo zK*9=>X6_&hqKj;99MfQbQ9NT%`pfAV{KBw87Fn4~5^|@cVH1R=6}wxyOWnRt7rIy- z?bM8a{J&0`(4w{~Ci^527pI&?IT;3GJLv`4n)EKjYE<$aMh(W~?K5r+r4*6bsBXvk zU-9Z3<%Uz&4&tg|?)Y5uT%`>du0+N9WjHlDDb$~ZiDLfzt+b0E+Yv+0rV>@LZWm-T zk~k0!HeX1&9D!F?3C`kx9?)XiTb;RfQ#=w1HJ9cJUwx~Bl09^kvzPLXIYd#@PFsiN+)7H5Qa5LG&J^{0JOV9(zIJ z68r@g5F53Tf2H@)NxvZkh}eibr!6l8hmjedEr3jH0Yye9H`sDP3h~isY&37OM@U0F z-<70KIOLvC3$N~9Aje6G*bFi5Y4#$WCVj$_A=wQR+^M5D8;JMN#I87uX?z|Xo*dZB z{bsce`zKOA`5o`X#q)+|RlRM;(F1z6!8^>D4WVGgh!MV&$?JgA#Woc(f#KHkqj;*2 zd=BwZjK_VeP>V(tSZC)p(t^90LKXShnj0}JZmRsa{tja7h_vJm(z_%v_y4PO@8O|i#r-{KcHuN+%X?O>iKH(I<_$J{RW!u1e%r_%g#$s>T)~f284bq>y3lPs zvO5N3*{2Ro!Gx;k^eiZs#z7*O+RVvepIT**~ zvgKr2xQ#oVbU231Nq2jHaeQ$xq;TFz;rMIJ{~@Fy6`kxvaEC;%)hWtwLgjTmKyTb% zx>syACM49gDcs;l5q0A3i8Go-?&&bA(jKTy$YQ zxX|lSRNZ;QzjG6yKb!)k2_RPY2-#Vol6SjY>kkm&TIO#8NPvBk&*fXK*nCP*&zPrq zle`=Zry)xet`IoMK({0Q)-dz;`%s#syP1w3!o&*|UQULZi1xfe(&Jp0+;S402c^cL zSe$U$18cL0S&|Yn$C0cPCdC{J_BCs9p(Aj@_40t1a3 zr?_>^&gue5rnQXSyMG{>u7d2pb(G|N*!jUsG2!ZuHjCcsHJWp-wwBADv-TwO zL@+3Z!ja`as!VQMxg+buFmYSCj_2?+LchS+(J9neV}YpFEn)%Jl~qoh8p$T%$?NaR zgEn_u0J0t>ZRAv%{f?ZyODV%-o-Z~W6sgd0JNi_maW}6plgNo@QEtwPQ4pfd%`@a7 zk^AXMvMKqECGfQJIQdK@ffTp7qWa}?sH7Hvt$M-egd?kwLCRc5S@S%U%LF90iEy4` zbR)v!f1Xs8Sf#aWKQY`yxgKik?#(qx_1^pYm;Xg)*)|XzHZnc-O1)_7AC&~dY`bI4 zJ&)+Cx)o@~ZPUF4J=pYbNjV1(W2Ri@S7~kId%&fuAqckq?yBr}VnaFD1-vOa;hhXD96;hXqnh)ptdgBd-PWkv zqic2voK)L^lQlk;9P5HUICrJk!l&ZVcmY?Ah49ya@%TjOE=|N9dpXY zZpJPjNrDMgiEyVm-!6so+`8e|d{ex6rmA|IxSs7`-LBZxce=IZ{vC--pjF!oTKsRp z_YR(Jt^l|0|{D_@9)TmE*q`WZBvNQzgxa&%(jR@}FP-kCgiV zilw(VSapCF@`nHj|Cyy-C0(forvQYe`sk15w(*fDbpn`?B*U8u@bU3+2JmUf^TfT+ zEgo8BrDe332{rh=XWC5W^&amYrLw`}+al%S)p} zppYD%um%=x|MlG*Z==yCw`E5n_{4)?L4k?tX($hzSL6342C^F+#Q{J9_9HeHP;B7G z=SP7^ddCVA9tT?L@3AB2*F(1h5BGCVw67%K0hYHj{qv-f-Rle3g}@6SE-ET{=gQ7M z3>*?5)Cb|mi+&CC*j51n*a<8hkH8Lta~F%!^+0RZR9Y1lmYbVPzc#3a9`2xegbec5 zKTivQoW=%o3>^sM6AeQT;Mw;RMJhc4OYi9K`Fl(+!kPcwM~=QXu?H90hp?kYzzabR z1KL&rN54D|jP5aj;OqbV0|Wu|V+9954D+GZ!8hNF)Q{L3*pC3QFo+xl;YXAOC~N16 z-Y2glhkhN42I7Y}_fIX|$@V~rdj%cR8HiI0(5nRw%&ZaxxK|1JJ9P>x(9bi!Gq7X# zs>c-ZCF$5ajR{ePxiAPE!ta^*eIbVv6ChCY!ozfQx;nq z#sPG547{lD8`#bm|GjwvBLqzB$5^14kN}YO2jB$W9`RkJkGc=}WfStlxF>@E{V@Cq zgk2{Z5ITgbzlPTc-L{Sn#!vLUFM#3q{OvRX1_X$IAK~BX^a+eu+&9-}GRDc%>c_>G zf}O7)&0U1gzuoE8$6CHmst|#Ah*v+~L0`Q3u;zOlrDrZ6U(ugbB^A_j_&$j62;d-L zV`6`RxV9j6eo09bgs)j)QT?}E(H|mp@ckf=v9IOZWzp~L##=n3yB`IJe+a%ECQfZB z7|`u^+KDR<1i|4M=sWlQhwJE9>`_nSN3G=7RV;(|=BD?%%NOtmk8ch52KNr!UPK4) zDH-M|Ud@32i){(%CDrBmuY6nVsIRB<+#VH28GhFGZ*#nztxOvqj0K38koJ$kl%C6@ zo~C0ck-n(7?OW|8=)V^dK);i&B=ljM%diLDB9ptcYso%88j8Sx0)oDfGRps;yJ&tN zppn|BS91b@KEGN-(7=~3G6p_j6n{ajAb{E-C~#IBd4rxQB@HaX{mcE`n|Hs!{!Y%# zo}V5>gRipxTb{g{!{>BRCEAbf?+Po-34CDOv@`*MgF?-00jJMW<<=AOKn%Ip-iRje z5%R!P9;dgDB9iI9e7PufevAs^?vwmq*%s6S=vjeUT%u7q3`ilXBtJ- zy+?M@O>^UfeZJ8n@xP)GVY)ng95(UheJ|A{3ya>*w6`~ZI6mxq!%*EP9fd00DHou?X6Y|S{m2VA zz98knuj$uKiKs!ye0)lc!>^p0v-4JcSm(_Ut8;HI$aPq)&^d7ecpDUk zc~8FU0re;xCr~dSY+G0emnn}g;Xd>E?P9N_9vt$<*Cw5F2wc=qMI^ao3d#ptIsJE= z3v*Y%woG|O9ctmFSrd;L$vMD@-9K|#FLsm_57AYV z99{N3IV5U8ZN3F51L=JxdhR571=H=l`AB0^Q*?aL*l0OUP2%`r^zMr0`!>}%=QriB z@~kv;apM|EYE*C}Q%z~Gy49x*(`L%$v&@MAEq`F#QMe4QA3O1-F@ktzDEinmu+=>` z8m(_F(JP(m;>?5|d40zGq)cm5z*l8Wc5bK5ZJQKmdQ2}`p$Aw)t7YA$;Q((l&a{99 zO}6+;8xCrnB`9%(UagaFLUUkrz)VAZ;uzBoFaHSQ-6!u01>8GkQZvAB`Rt~rh%@3w|vHu9J< zshp;F%33RgI2ETXuNIW+Mx4{K``QG3UfD|X`BCg}^D>x4%YLT42bO$5e!A8|%{7(Z zZI&DOFTw3yzRABQ-yXlv+f@CRF_VH(;(KJ*XkZxjN$#c9o_ORQqDL6J;E>aFIKc@tlE%~4?#Q*Dm!;iI?a zE2zeZ<^q{5c9#noP){Fp&o&day99o-#H)l}YN1p?&Z=kRxP*^5u=qmFb*oup_1Tv4 z4qKIs@`yf+0h@Tze&2+Io>GpE2Qk)5&&NxOJY}s1F~XZyufguPOmuSE3~N^&tL08E zhq=F4KVQivqw?qFqU9X|qwT~42 zB2zj;A|N#UJ+pn_N&9%A96GH?{8z_9swL2aZ)-wIzFv9ZC%2_MO&IO^S9R#5^zC z`^3?1{XC_=O`-fGIu4X00LYl%8J#qXyy+6(Pw9bM9R)KkVuv2%04wdmM6Ke}C_N0@ zp9ts7oM%&MdoxEwktkF!V+Jg{dgMQCw&1k*MrSERTl?;H*tg2XT?vn4t{+Oy1Hseo z*_SN9%cd{!#!jCDfOLCeDF)r8MM!CFMXRms_GZU6Ha<>B59y4( z;qPMoNfhI4Ebp1x2RsMFa1uWkz@Of2;u_HuPuN(Ze3A)LtgKumFZJEKr^8=`*euBt zU(&d0pM=4SN;>!K141i2u*tf?3n7T>tsf!Cd;a!-(3Na0m2%jif7E&Un7*nZrOyWw z7}r@LpI?NEuW{_-1)Slmgl?11(2?eQz%#IheHMwx6?*&?RA1a$DB@Z2RlJ0D!63hU zE^Lnd=1Rj6838_7Yv!f4VhwBMdiFm;hxF}w?BaT8Aiaoe1092;5k8d_uWZLhQrG8#71Pr z&aG%f;}N}gdMEN$L|VxSb51Gm(L&IB+;m;{xGp$qrTK&)zuV$wzE1WV3JSi>4$Ot|yY`R8_wG9=tETXc7W-?5)tzobjVwE9Y9xIYzWJU*8Q(7|%02PVgV8Wz6 z72C$)8k2%H%aTqjeheu}r%6aUn|``Jn!0s1d~W#XO0Q|(ATlk;)`Ga)N0)D`^@UR{O6V=ahLD^+!1X=mGzqO zoTx{1(+uhG7fUz#Yk66#DIpVidt-_nT?*ZhDa~1Y-K1^yw069ti`H*{$>E)wVcMIV zIP6o;!b|_|mz-{5Kj_~R#c}VM%whD4aU;ex{3Q_qYP96O(+BEp29Ry-^C?-bNm)>& z%R>HXMRhqjlnK!bhl-cG8iC&E zPG>#u3dkiO3MGf-d48(XJzUM=gYfE!$>vfrtJ{qZxj1mx;r?KMASC1}2R*GiZ3yaV zNrCyZl|-RjbPwt`xZw69gi`Ta_OOQGicvu~_;LY!0Os2{&&0ndm4ec>bqq2}QeRdf zv&`xna7j=3U}zi{9+^+IA8Q7daE9D@3m>WijPH{K4~+3Z4j!Tns9bk)0*}|kM_K%A zyTBZ8l3|(s)y~WU^TUEti~A zO{qCRLI}T%yg^BTiZYeXbZOUwFN9sE#^fmIWttg)GK0gYgg;PUk>XR zuD%flyK3WjG^X9w#tg6sAcj66^_ zgq3_9aI=dR{n3i)fbh(F0ym$)fa5*M25RO2U?)GL;?qPH1u4Fwsj z$qitE_vUD{CPy1((YnWM62fwFAfUAOwk?N!DHeI_aA z)GdYEG(8Eg@un~(mV*289C$Y=WOrQ_@$Sa)5gROK#VQuK?OQe0`oc#d$ho54qwY!K zUffQuj_n|h1L;o~vwlZ@Zu>K->*o8@fwn0GhiYp97rkB{)FlfsD#e zHAE*e9`gQeC*ZQY7&x|*AA;Obk(gO)9^K7wPh!|&?=8|*B5EHfmcYXK_fQ~ogkou% z)3v6!2q^t7t);U)EeGPGg zi=4MSm8){*j2K_U3E~os%Q7x*vlr7(W163n)=BWO6A7j8QL1~_u;7*kBDLs#$7)p7 za1v*!ZMSsRWeXG?aOf4}e^J`iH`b&Q!lDWTbK6a-`670&eA@qDZ6A8DDVTXjjiM<; zK;*GC{k!tDJJaMD<;KfkXyiO8(8x=}fohc%5tG16!?y~@5H)dC==KD75A_+enNB3I zE#|N|RDHyMoHWx0w|t*0$DGr`D+AgG#M3)gJpykMi=Q^%c^NZHK?Zd>h%O!)r2I}g zgfCEeMrHrj#{^E!k&kVF61-ORdM}TaX*lXL7u)W}uAUt^V6=*Yo$rxEUgh2yb= zt7nh!y@IVW0dl-TC|9&pW`f7+mx)o)oZnEqRe-G`Ln(kRxEn%0ujC5J12TrwhJQ5xX*6O-Xvcv_gMOE5b?d3}iuumS9Or1PNZ3I1EWhyE)v5Hx&j0(4{9gWnjxQ1*` zCN~6N&o0hRpBF6K+|PEbSp>h@9Y&DZqK{zr93hdzy2X)wK95Moc208U z_OM?^dvG^Zh|amhpH+3Vu&Oq$Syk3CbI-h2qY@i5lU zza(=U2rwbgr8Sl>B(o%AyqfOBe3iSOuk$IevJsG5r-yCN*l_HuSb5iKApG3*QxP00 z!cN90I7gfM8zSwzYY&(RU*Jn{lkItN~zR|o6+i=+ISL>r5m`OGlLt&_!Q0R0n5M?bi_qjC2p@g*O>r$IO_}9txXTd5 z)S9D}dPJ*D*r8UUMRV54bD2GB=@xY$l4G{|6SVVbfdQ{KY7#^Sm-xKAl{RM(YCU8q z!VYK!vahXoE}oji(f9Om#So*%g6Rj&vd!UkICLWE?Ba(icDVqby;;BOOen<@(hwVD z4uhkr}Gq`}IVvSR|prOh*{mZc6CoG2H; z#NiS5BA@EfCnr=N8>$-viN(R)2m%*-ALbJYSR*%m81{BG~ zVe79}W>S?*0O67S4Z2np%2MzVi|(p&a`!NHnYja@1({k?nul_>>(D}rS`b{dhzaD_ zo^{C@BsKNiw}3oba@V|!4u#2J{8)usT7gbh!qt8rHrVjJ9^56N^nSc|d5y&JRoULm*T+(varTlexje0kuIp>~vQEQ1!h~F_QgySOFqp<# z1v@PgEtnVc?yYjo%bri?5A{-tcU$glhU|mqvN8d8@@5PLy2`EEKxWWmWJ-NE5Bhc2 zFu*)QMa+2jL&od&1%K=8DtIgL>OJ01JRz+>YS0YfKy;~Ce z8%)~;%={>2GVUPvXZKz!hmVp+{rv~7KDyjN@~5-Aar8F11Vev~EL?__!OX&}94TUh zsZr#K%nf9nG4Av!*#stochfZShFM9_hVq~Lcei(S2kQg0p{^;Mh0?ao$kn2V@tlJs zx$5+K{)A#2+MV|L*ef=j(DQ8YuG!`jTUm5D*6j}9N<}Kw=P1-dx>Mg`H#(a>C`E%J zUx;0-wRKOvt|yZ`CA7w`xfTh%zdMg7h}0`<6IdCO4abVQ=$}5xUlk;|h3*9Zq+S`D zAoLRYwsojB3a7CqFTY&_-u`(_|I&TL`x>K_ymjv+b#=6y&TJ)3pA>gKA?X7(4?B@< zOWfFz+L%0I3UQQfC#Uvwu}ec``-352?~c_H@oe%~vq+B97vaBa{J_^izcFz?y+`NR zNEXjNqQLi0(V|-MqW4E@WXhfouX^!Kbsna*%}d4YobxWfpr)C7u#7lix^MU8{=S*6 zP!2IPe@PV2RG>;bWvH;nn1ga5QYS%Vt`D5<;mHMlPSZ06Nz~NcCt$!myIgzbT3BUX z;!j~l15@qG-RtnIvA3BDO%GL|226c=fw6xqBKGzwHuq-s^jDvP=A+^t3}`5nm`s1I z9pu8|>|%|T36*i0{_$2U?JIlyA(&?X#_}lvXmsKXy4udDNqjnhf7f-efAX}jc#Figv z=WWP!m%agTH%>4G+8{HBc!njY=}3g%H$@4D8&#QL5zrKkRN1lne#;tw5FabhO!^xA zrD@DRdoc6A0Kh!jx&Ir4W1#<^5RQ?BgZ00-8v{NY<9}f{MtnvVW=7`!KMH5np%iDc z-9V$+!ZE40-eSG^A4i8}@})|n<)(Lq(=vCB%qA*T_;OyWWh(54J|RhdYG+1dc(Fez zJ|#ZJA3Be^q+npIuMa>!&oG351l5I+#i_oj6`8?_;TWhaGXo$=1_vNY8h{iGOcY(w zudX|=G_kln7}{?j?O|8IFC#iXytuj;nSXj`WM_I|4XE$%z1JKBmm8jvw%q{L;WBng1Ylg#g5 zIn%GcJ3IWimz`trJJT;avpjKOuhWLA6UH`@z5!I|GXVEL~?0+PO=r7OIq%IN5<{Avn6!L^;0{^j8%NPJ6Mg9{_@ zx73##*_2=5A83}Q=BE3vU(jE?prXiqJ_Cr2^k1TXhF-yx8G{tu5>luX+TXM5gCmQN z+`5i)Uk@Tn3xjiu&)mb3U$X}}HJPhxEAHRf=-;G=+t0J&CgEdatf7r`9BDiL)>|O8tL_6Pn zo(Zqj!Xfu1cBP9<3_*w;mTR@eLnJ5*ymqplOpAVEC;?kYXFdR z5Idor1j7rh~O1;R$VPfD=W(CMpyBDQ>(lK14!$TM4Qf)9}!sVa7bOfCcJ)Q zYc7AZxmMgM^YF9+!YF}y_v3eWVE0mo6MK&XrZnD@YEBfQBX->njLR=xqPcf+T|MtJ zmDE-VT%(}u(ur2LlQoe@0w4{L{dit*TY2^-Hj{LnSBn~PJ5UW7wWFx_}Dc_UPohsg>iS24Uso!X>x}MLHZk-SjFN|PXfJ{Zwe^0Qs zc-lZ8)W;wFuFx@J{CwcP$!)(IvFqlcZ6>DhRbApHYoYCbi09uyDhH76Y$W)5UA_Zv z0&bI(2?8!abTioNAIg(M3E?Dd)05;P9wS4UD0ntIN@o3*%&h?22tOh+9hGtGL=yfzZM}-*L%l4nRU^%qAFs@WRvi_- zm!>BGrdn2#@8@q&x4SzifV0n>q>I76j22$KxaEM7C3*^r^4M1`YPjduTegD?mEK4W z*HeRpa?X{|G;!oi7YIw^v9~-(QyVLQLhc)6vOTB<8{jIBn*S>zS(^(gM|Mk-as@8a zk3ZLU$We;-+K-1O9oT0;Si|{zNoSUHO^j}^u4;>hS{xryZiBJS@coe4sukiP3u7hI znh(7@eB>!t)`auAuX=jMJU4u`HA$Sah!mNf1btadH(+7iYD*nHn_1me>O@BG`G>+? zym@LWtz*cspoggctsrR1Ltxx{eLL6_jSFKNm9a+LTCpriIKEa`UgXiW-2ofY(!wjc znV%iga~rz18>AXMAZnc36VYkIYX+iWaOLv;yrpU|a$CEPmL-R{WVBZ82q8VP=9DM6AQaBt z{Oe<5LUo4Jl~%61-*JWsxb}4;_M*NiELW_Hjc2=(ff1MrH&uf%Zr#C)NrADvmP}&{ z=jhtNYbrJ)0MD>*_F(wbdFoI_nrMkSr&FuH-9)$%DebP_zL8>{8O%q}>Z0T6bA}LW zdGG-5+f+o#E@(}9Vz5kpNYm@RuLdIzW&<4LI9lK9W2%6#{jk<;Qg+*45WQ#4UC>s> zjtW1M*|2SOl0f$+{wSd*k)weR+e3}w$L@8ci6u$7Q{Xf=X`*d3#ZN?ep_YLS-(rG= z%Tv!@h`=x0-ii!k(+?M1tuHbaM1wI1Y7vL~3I`h~4J6*T4Lan5F#PRP`fZgy`;C*n zT@+zi5C{(`huE*hOxlVqxff#W%h_8#i}fJ(93%lh*;yX<5ROu94@_@JilPiNxskAu zWa6dH&zf0&rJ{}2`=e4FD&9*2JSYlU?44F2kmiXlyAs&C|dUlZU$z}M{+kLKN%fV1pl&l`|spI;$Asv;VguGV>bCxXv z&T5^)$LM_eYn=~2XA|7a(twa?(LLP2XYdt0Gg4SMGw$hc@~NVc^sY5-z4-`a4|+1J zk-??aXdOu01nhX;HV?g{VZm5J9o{J^l@|7_dtf-W<&4VElzDjEejU+^k#FC4V9J|< zPv34tSkK7m{5st?ZF^)xXE{~t0hhBdaQ_rseA27#d<@a#1uoY)J+^Jsl@OkfTxRnH zpcZ0DsX%BPVAwylkc` zz4P9ekiIXTp9|G4s%$%utIAi7JPa9^;cAPuK6(1m6LH=G|DSZw4*Kc%1rsITu~SG{ z6#dA`aZ-R%sS3(n&z02ReX#f?qcCHb{!+3Wmt;({mh?`2^*#8?QLS9ZwAw;2JELZ7 zB~#HRjz)V~Uy+WCdcSM;(NPhxegZ89{bh(Xg1|<14*tK^=xXVEm7l^Ife|D#5XJ3U z3E_m0nx}M|IbrRlwBzQZ7^P@6JrJo>Y|vzx27xM8rU%gxR!rNrKMz4n-Uy@^YSTqx z6$`i#bKnBzw6{oG3q{zr-QW{a$egc64n1hSqx;Oy;gbRr4?o3g|!PXDZ z4*j&ylvrVu#jVYT-LGQMH$}CdCCBRZluRTz=pdI{4Zk((4{qJ%y!#Dt{0dWZw;mV& z9f-7a=*J|FKK4MK5^_y+MB@kol3_q zR$O5Y&*kt#why=tKifj}=MNZ#EW^_ugTfQw#S{c@EWMPT^cz1_#CoRJrc#P}Q#W_&oD)Fq-WHw+C;fDko zqAkmB0##pzx6!0t!}{nj^rHt#qtart(aZc{pwTx#1`~K@jy+?#vElN3~8V&bcgWvqIo?k@MnK_kH` zZn)b=is)q#aD`>_WrrmTaHF1R6f>C`CF~lJE*_tuLUM5A5&H6V1$H(`G)84yw^wp# zh31O|swkzVmD#GaWfd`}4|dz%#Aea|3s~Cxa`A}-P^Y&Uvs-58kA<+&K3KVkq}W{* zUr-J~lc0+D%$};_B{A!>FM&Ef7HvoIuIRfVzb};k^V5Q43NvgKh?tCorqFHnTFcH2 zidG&f#`!L3S-yyz;pr+56`FW_)|ddEY|B!s7AJP7^SY80#H0k*mzsA4aGSeMp z;XOs+8W-vYLG_Rrgp^_%_Tw5!{ow!rTjUBx-+n<_tzoS;fhsrc0MIwoQ_$#C0r#`aqKg2g601@-@ zrfDqlF-#|eW5PVDIrd6_haGd%E!x^e=H>HP5LJKT-p@{Y-<)HHa&{I=Pqe<F35! zD{>M*x{5pE*jZ|Ywgqb{_+b7piIZlxh_&aaNiXTSURi-vvysl23P*LbCr340X5glY z4sH8#HD=}(Tr`xMWWip3P0DpT^0QP2JUt{!hKA5bQ}5HL2HK{q-Xiwu1+Xxr6?SCO zd}u`4uv5W%6@JuiOo%7O!ij~pCzdtr@aunsvOc-RNkl-P6^>Iz%|?Gs&3kF+*0y`K zXNYe7TMB}VEjo_KILob{8NE_5o=t3Y`V+%3&Lg|Dt!mEk5{kZq7=Px_%+zlGHCg3K zBy@Mzr?OE{-k7$+f z^D9HJ4>rQ?+Dc@bp%2s>n=LP$d3wj-DT@zz3b@y?iWiwLcv(#ESpV9T4^i$Mr*NZRR6_q0&ri4yx*^gWhkMkD>2YBCLvg3|-@ z7~d?rrDnf9-snjNrvCccol%a?EUxMC_6xJdg%SNV_j8;F+cU(oN${i2Xi<(gpw^8Y zw>&;*z9UJN?2nm3&#i%4a5~o2X-p3wgXjkwotm^G=`itEa#C?-!CtO><)Xx}QZrO3 zEf+IA2&W3bNn8_V1)o;Be$0kN!)$RWYUVOy0ml@^+)9eKHP108jMn8Q^b`a}os2SV z0|aMeH(Kpvbgm(zr(#BuUTob*;N5V7Oq<}0(6V1?Ojc&qS5kY~77X%{F=_{GHAG@uyzD^)+u?Gh zQV2V4g=j^@Oq7gnTcu3iZ*CQwYEp14?+KU!SaAqSOQb5yt!H2#x>+jcWrzOsT9)wf z_LxxAv*Avu>Jr>c1!@~siA#1o!j~p+xNWd5O#jxdW7Az%gcWP)B+WG+-ALNk$!$K5!KpdA$FLjed-l`H`i*TFu)^wUik321R`hZENmlK&>b^R-UhOg4nP8xwSbl!W$QU41Xb2U37# z8;j#w!6E}6;N3L>>g^;^+(@BLtj|Gx$7mNs*_N2fEg`lgQwIMm1~PSuZoM((&>D~v zTw>V!V+r8K#o3%wn8;~*QyCL1?^CglF*}$n?925x|tGiM~2FMNdHw-kqWRv$5Iv$MR)59Eo z6v-8n_7^88y>AwGI!uraz-!Y05EnfSs}&%tA4D`P zxR|g_YlBH5!zB5K{<`nl$@_fa&v}hTGWh>~)w384-H!F`_e?qcNw>md3LqXpET#f# zGQg#|u+Nk&VO;Y?a!G>kvb)VmZ#}jLDQ4kuc%lhed;nv9h6rI$Z-n#U9c_%*lJz#C zBvY{O4CAO@0y+#hj1a(jNq46akqhN|*nxD6W+OL^)7`ia_p8ixrpoCwnv14XT_N_6 z2Vs&vUf;a3u=d&{AO5-{XNANzf3V5b(k(0;0B9ZI>ESq*#<_vJk6$!{i7Lb;mix0% z2Z)=L_7f(%Qj*>nJ$d5KaN=k~TKW^WY*=D0?yZJF{L#S8QU_FH1{FY*N9E=BXstwX z2^~Z|flU^kq*!F7ypyL&-(E`G4KO{|JKT-yr_Ce=AED9J-Qq*?9%JIVryj9ZHC7%A zAuuew)|Z*FQfuy3W>t|+6lcqDk13birTk3mw6}+OK3Z!5x0swKtL!`iO+U2Wik$Lb zEb2n{XUK@%u~lVTBH(4D`Vj6m{gxhWozNhyHEf$g+uZD>gcnAR@Qz@ntJ5`&peMA{ zfi%~KqiqJ?J@xwHpx=(I9qH8}dS*PN5yg2zuGf;8fqb$>(> zxGa%w%9~fzL5MSMITJcvsqGTc{>{PE2vBT|8aWLlZ#MR<0I zY+A|Jon~Oa_wxre9wstH1O&cU?z##0BqnlX$5p;jt-pViOuowXCh;>wT_D*h%d_@@ zYdqcho-tn<>=F7F3kiiKkr;@z%r8^@| z4nzSD@%Dt?LgPxpR)QV_Zz)vf4OMRA=hA>HHNYLyiihb@k8EPoZe@@nw+CW>{I`&j z6A8)I5@oDFkQI-I@xzLAIc$RQVN!Aht}n_;H$SDW=%K=Ef)AVeRYkpV!%J2Ig{M1o#(|}D@VIH4As_vEcE$1|3_dybjN&Bn^r%jyK9ZI5l8F|8Wnitfb;-{+R_=MpYXyh1>E3%ff*bh33>FL_;8z zw9JG-pd5ut?RBj+1?;mQsNn18X4rFuW>$s^ORYUjHf%LHC0|b}QRW<)^ z#Z4$?J)ncgOy2$Av`lDtVSVp$&cDP&_0 z^JLu%mk~`ly2q0NjF|U)QAzSv5m6H83ID}We&J@>_npeh|2pZ-KC;~BOAnb1i_A zS(B&5l%{Xa)gc$jb0fw&fUwS=UyGvrFV$@$Cne5RV8mzS1>&iyYy=3{>R`VJ62Ym5 z=6rvzOBjQbwWC>e!J%1c!-zMQGJCdL9C6mzUvQujF6>o56nTw1ulC>TAY{ ztdTt4T-b=;*yt#_Nin3rvbVJ2rOmADbj<1-N&>`TMWz(*VT@3e@}7-Rg;2LE)Q~Vz zX;X!|!}rqIUfbLcgX^A-S%TkC+MC` zsWU1?(4L<+476%&Wm`ElMfSJN%@bF>Lz&4Q$ffM87L+CEvkrWwJG;uQ;<1?s5OXN( zL+dB%pQ&f_3ZQ(W)PK($9&t$vFbU0gib-`&00)>D$WV&?Y@~1m{=E6?6(C|D!|-=b(+wkEcG7y)vY5OliCScF33wspEmtBIg_AYWI%z2hrw7)G;vAPXm$@F+SAV z8NyTpu42Gu{@X2GP7%?y6`_^|en{q^Gb}V8Ab-}e?*76E{&&WhNAStIt^p+MF=4Tt z22xe-e$WElV=sa{PS53svm<_gk~!L$*^=umi5mg;EL2GmY!oE}I>Qf_(TTfJoL4lW zXe3R+s#Jt~ZI=#v3G;#}RFaIfSklW$G3$!the)ZGOOYr7-J8c+!cB<&O%_joYtjWEr4B@PV&ekpS2A7!54pN=$*p)g3W_ zV)oK!70yap{;V$SR-H}Tg2Hh^e$nj!CdSt`RGxM}1btPC!2O^|Ndr1$^4W;>`w7#H z!2_pTlU!CcYe^pNUp(?nT+`tA#~o!J;>w~r7`ky~%kDlPl5bf|_h2oM==fE(DY9B6 zTn8oR98aaERL4Ib2h5kt@Aid&(`l=kNJdF?#i4C;&m2YRD&P9bnvx7q#Aj8ay7?@? z8Yz|ThOfN0%Or3p(ydMff5&K(MJ^f8+tlKp9figG>ktemsj(K1=9RTU^pwia4lCbV z(6v!iFwSX>V0XWC@ZOMzCk$%!AB1P!1kYcWddlYCV9GN3gG%> zhzS{3;UvDJp^r2C3oc+ze1R&_Pz5i?X(9LSv!SMRqNO2 z!(2#yOf$@Jg zdyKHBorF2~CM{Tet1oijl3r#9h96>-jLJ=tTz3qU;NG9yt(j2w88)hYYwo~0D#$>; z72BdrCS4>>XG@nF%wUx{Y)V)zj`gc{pzjwRcat_Qp?Vd+6L`1Gb!t5&a@88w2MVkE zxIOBK&oPG~gOIk0msQ%gg=t~9h09P%KO&-8*l~+xU(}1B>OvOk7BXtR1icZowd{01 zSb<(iwcvZK3Ka3A7-p}us?`%9OSj6&d*w6>11;G;N4)?lxlYFiM~g`HouCX!sQD~9 zEw}U|ZUw?W5vq;tNXA%^9Fk^GW$vH=awCaFH-PD);BltpO%Jxy!mW0*D})=hHaoIe z?j_p5Es74s3_6P-#FSMhGo@SQ4AyMN@J-y<&+-*72|cB@2a7#=$@axdI@nNrx+5V< zRh2G09|3jM@5{sqb9FTqr!_j2qA$lRv#CY?KG4mn9#ST4mXI#?qT_>cg`UQi_qsOm z*(6m71zAJ|Zz}j`>C~kR!xLDwqZ0(0zw!xldtHk_u2o>m7M->g>FTqJ6!l3lwyKOr zQF*vt(x5ezA57NDyYrCnYoh4TqB!U#>2lv!o(N+DXG@BSCseR5!X15ZpMA+>1%F9{a2< zM|;X*A0xLoUO{I12^18YL+teiO>rl?We(%(fmQxqU8edCGhD{YEFQhG8Yc7~onbtt zYF|(XeXtez1~BQug<0dW%#RF47SE)k2*~|`DEDB{@@#fQCV;OH5`y*mKvPB-q*hH8 z2+4ZD&2hqT`9A$GX7}jD8d_Q(=bD9p5kpN-nFWA%YP@FHTvovPtY(7IYWv@_SEzp`ac32 zZ4`%Sy5_8@h^YU%x&5vlr*5pDs>Bkc*70o6+}_`KU$*xGF;e1z-YE#l0=bCDDPEFw zAInn@HMMAQ$F|l=*~b$~p`%{nEJG_yw3f8H{c0dEt8nV{&;qm12lazMW~9R_ZMs)Ws*?6Z$)8^89s4@`dzr?p9tdL z!LKlEoSey;lO#z;vZnWk{0QjxQ!2fOK`$L4+NKkR`=ITCEa^Nl1XTl@o@Os2?G-vP zpR}P*hqx-HDA@DSvt_hDrE3)vb5Fo^02QUq5K*m^wG=R#h&QArjdz`oJW~F)h2uEeYjlJC*Z3^Y6^Ke~G z&F|Jbf%Rl!h!D;$orZK?#}A;8GL;Q3iTGPH4z$?~>8M&9@i15r?>YWhUIJOW^5Yu> z@i7KfOtNa?);!DIq)+}h`9t0J4^wP`m1R&(AY7k`GMy5@2uhHgtpu`gIxRT18MxpG zq+BN~#}7PFz1)5k@t(SyJ8(!)LU(|VasGZJ6bOOuJFGE`N#d??2tUz32zc*Wy3l(9VqR~%YHeh zcWqURD`*6tln+q6t>W)Cqa|36QjTk`6}ySk;B@~OTk$f5C5jEj#dPcTQ)3Hj)nZD- z?SzT~!L3=IB0ry*-lJ&%={kHwSNm7cx!+8tHJf*Po@OvEq{U)(SyU!QSw3mk*#hn- ztZ|lOi0IAk59%rl&k;Vh8t#ADZJP?|%SG$Gy`9#vA$YnQDlmD)v3t_W9la$9FTpRT zSNH|ZylnD4iKg_d%k_U8p)jcAZhtDu7FebUllgj#b+lOpm0beZDfes4d95oVU*hJg z!{R1`>-orkFr54fUJ1i07n%&?!xpYEja#+BuI(#oM&f_k`s5{^ zow}NS3&UQc_a;iBp@+>GG_OOQ5F#-z3uzE;R`qaQdMs=x4FY6|ON{A<%jFBkwN(Zl z_Wqc-%^DF@_e8GJqnywMhLW@HubqFLen%1@3(+ z5FUS&5zdp>?^Jaz`7fc+d!U&T5D`U@H89FiVHHd35`n9E0)=DDWi=nY^Vzvdp)#%5 zqDRkgK(gM_f>7PVLZRg?qRyF(qkFzFR!Mc&PnMqS;wTVYJ1voZ0Gz9w{p|;fVzcIc zk6v_r=i$}Ut4d-4^etZCkpd~CZk_sajJ_t%^ee{uQuE+8#BI5I`j%e4`kqKJx6g~f zilpd=t-&vokmO9x$L6GD9|^g|y&NQZQuaNA@aN6#cgAtADngrR<{YsS$=CDy(FY;T z@U`GxfO8QNt@}&G^LLz%A2{rAFbOL% zP}*EuwvK(xIUI+W?n>=74QaG3>Quh6{so`A)^qA{jX#4RC2JbZ3CkbaDY@5)k!cy; zv2H=xV%x+$a#0+U=Xj5BaJMTSNDZBA=REEqMAp`PE#U1 zB~q!`^~i=W@Aehp{%k04*=xG%Z!GZNa<<8+3{hSDT8+P+X5Dueb-cA+!|9F}r>cpDqh#VbOnA$< z$WR1s7svZOVut36)ecHyw==K|nIb&%V$-rCif=U(x%dxh0K0iMEyAw|}T7=7Xpbcn4nJmy45+vG{pJ_MNKCQqq+Y?*3m zNP#%n40KE zuG#NLYFc%$aZR%LstiPLdVStDFxQ~bzapPq1TH5DqAq@j6>{{qy>Nvkz3GN$CO_qL z-?hzYK6)J?4IdY&*YohaYf~xuw^AamK|vrV3AiJz0jZNo0ZjBhtDpWdOmO#YYi{#PrWb}qqr5NN8ghfO?g5$uLCi1kBn*kaL;_@Gh=`B5t^C2c(jk6sl}<=&Wm z-5+f$6I%p=mBsz^!XY>47j}kxye7B%+@gvL(xZ692Vv3GMwYkJx|}7Yo3oGH$jF4e zX^x7WmOcjm34Xi@5T9s28?CHH9%rv*UZNLZIw<1fD3Y)4y=QWq6Nq8fj_!i4VAK0m zmE*5H_P1Y%xWwic`m*$NSsmKEak24aC%D1Nr=~$0-p9a3aL=ZY0MsV8|9}O6TbJ(% zWFaoMBE5s1*=(P%kh$q8aYmwJXZGfB+_iGw7Bc26?|^f3($H^08(5M_UTFwC#gAC) z_F=+M1OcZ_&NbXTyA~4>nKa3qen=~+sHBuAdPpH0O8%+mFs$TL0QfW^^m)%R8uj+C zV)bb{^`S;6?@zhi@%Awl7IgsvPcqH(+dDGvkI7#K6{sKJ1%wN5!a%VZ%K`n-Z%Cr}7si zy+ASgl-odcb{>|-&dHJtm=vQvsVT`38%ZT}m3y{__7vt9=E5G7;=mv>Q4IW;uz0!$ zI#ZxHb-f0S4g){V20F^i$lO36FTaQCBfmsslP+AykoC{XMhEr#u6PHiq1!1;M0=Br z|Lm;v*+Fvg4~Zb`8ceKUS#*Jc0X6tnwmX7mR#Dj-$!cj9R2`{}mg74fX?uFb}W67^t_ zC~oz!;Rad7TT`(n6U#xqv$?qt{LT=9FPKE^iH{+fBh$!&78ml2A#~%(Zx|U;k6UYms_3p9 z4EBp6s}7`sNZl8mzQ{s*#ITo|OxUXz-tu7i@Jr;g>45Jm$MGgrZ-P-S{ zs~I=VG~2FK+dcb?X1%#qY&^@$X;q^7c3j%wH`L91UKm05RhgS9{2*e|r`o-MD)0v< zrLL%IpPENgo)6T3;!x(W{RT3ysZg9{V5jy*z!VZZKUdMj+G@-fO+{?l6e$NkZmWj% zLT8w4i45p9z^%9MG^747Jg>BMWY8pDxC}#Hr>x!={}2`bno2HY8-BuGmzb|tDQDn< zZqFmYVmc63v_?&@!W;1&Nl5mjOTvwy3=%bKn#e7b*2Q%B9(-{%^OPI!aCN9*8L6Ra zagzLJgV%O@AUS@cw+{g+b%xeB(nT=p@grE*E_ml<-R zCB706iA7Mw(zmnH4jER}77^|K4L3Q}!8}WfkYSIvY=W5KMf<|tH^<-imh0~oFx*m&! zvT-BwEGZPa?tJWe=CEH&VlhMgQLma`-?d#L+^Tvk#2mjfr|k-S#VfS3(|{hXZsb2ttSo0{P=F2gOux zy9LS4t#zRf+SEv{_jA&RPq)U-`TIDH2yiSyq{@^a$*REqRu7NsV_(-fwunQ;1j^A2 z%oeCZ%34H5mvRUvJ|0XfF{Ul&0}PV5v+Ab2i?FTy+aFP2!E;UJ%mg_lJ#6TC!w%2B zDh{IjJm)h3f))J6+861Yzd{uMG4k*F@^>vFs)+#{H4E;!rE`bUc+fA2$L`NH{ae7R zJP|yIb5LzlG8B>@H);iKVoLU-VPG9ob67Qd_~hQGE9D)?5fhZ&DY|lJUVnLYm6*G^ zd_v{JGXSkLQFAHonrKx|=#30>)8&2+q+aa-5^>1iU@{lMgtB3flyyG)6@R-e4*Et! zWw@e=D%9V<->f~4P}pEfIjc+BlwjLk37m?(gNgO(#8?=;-5s4Bd9f{ykHisvop-x_ zCruLG6dkNLT8o<90$#ElwxT@9uGO(aDC%43MrYnkI-gGJVRg9M1^bM5^9J*Kz4JHpNZ3m~Vi>xE zrJ4$qQ1U8i@%#c~ccr9BrSdq*XqA(dl!Ijx;oTHj=wA0%Q7v9O2wJ3uA91G0Sq4%; zJtF@pF}ViA@kN4#E_D6A>ddw1Rn6!qi7Bq)^*xz8g5|8x=-gqHOeOYinzpyKhqch{ z*@BQ_zgHl_xxQ{!2U{7OUkV8Z{|njgSE*EuUIF{rpX1hM5;rAFlbFenX>}e9-h#6f&IQD^(LjHw z(VR$dul7^dTB(5}ghpzf=wdfu#Poxv39Zd zBNqGP`0Fb z)T!s+UcxJo``<@RRye?2VUBGM&#o(JiSUaF=C(py-JKtS+>*R9$!03`Ngs>`vwarV zIx_P);Rf7TZ=Q~T{m}9Gm1%L?v<Y_9sWVXZQB-|t@;nOe}Q=Faxd`-0cxSXm*r7PX)z8Id`o=a5`jJ3$i=;=?T; zW+D5(!D~V1ue)ydnfEqVBIt3?6xUJ=d%e=IKiPd7=1ASN{@l!(aOhf78l1*1ObgUf zYv|%L!b4UxH-$U|3fzIPd9U;FWzVmvmd6B}|0#-%V*LSc9=f$&fcb4A%z}w!|1k0} zysf_V%w7;|@?Ej0gFDb6JI0~Dv}5#(#d*iLu%DBVF85sCIvPj@vy-^Bvr)7?)}m2R zcSdu-xp|heVWIHR;KoDoH;NR_P%7k@Nm9lu`l;d?%5XX_TR5$o!xS+xVhcgY&u}kj zGHl2fgo@=~>PY!7y3b-=pCwt)i4UB}zc`7XGiZz}O!~%tWl{NWNe2EeG4{s!T6G^} zqb9aiyT1Fy$#}rjLqpx&eR4-tt0v5*m`x>YR(gG;H%cq=+ap(Hq)KnJ!)pHaxHHoI zwFsl8FT4I3*!t+vV%bKGNHWA|9zMwt;=evQG~Yj)MGv#SoT)(C9z(Kx_5-1D{Vo5* z=c9-&q3xUrG#PJH!nKy%fRT>?<40;V@pPENd7+8pcaRFI#(CvAKO!56@cSw%Zr)!^ zj#g3PH1=ZV@#g#A_2ryMAFP3^%k zXf6qz3(FzhB)`@&EsOUwyffMMO}1xB6&NcJ*33?m;9}XrICC<9VZ;YSH4Vq3gBg=- z`U#3&@r(&I64b}_4twg60t4k^rjwun>TPd+PXE`qr`3SXvYt&@DkIgiTg=khL%FMl zq<-ajYf4X0+;XUrlznhAhb64E4Ptnt(DdAJ%9UKc{P~{Q!qIjn?;NrP;*^*uEk+w4 z9EQPpf6>z^l0D%rD!jVrv-=cg6ZwQcs5gZahZ~J-@*(MdTP4URVG@sE5i=tBWGLW3 z-w%BZgSXk|th>|gWcH_qZ{u>`+N&RE(#M^bwk$idyzkt$R$1UdhmGwmSrr8@WAe~S zVC#4l?T>GBfaxDQ2!F)T^2cm^-gLwfT=hXzh$Akp+xs|lT(&6$PxhkFC)XZ)w_Dzl zu)tq_fC-2HuWNJcssvEjXy%DiC%Y!w)}#rOZQHgd+nhAjWZSlllYO%J-jDCSf8klr zm%Z28>2~xbS<^*T#Wsl~^gjGz5tLs9TG8&V>vF%3x*Z*Ni+Wnl?y{^mY3d{YbTC|LmRx_Fd}-BX|J<41td0L&dXY561} zzCcy1ZHG|btiG4dUS#}Vwm4b`aa<5RJvJI5Jr6PhWx zFwBfiD2S1;HI1vjU+f+PpGq^a&|wI~3aO*3Jkg2_REg``?Q^Q#4V)9P&N;CnTIk~H zylI1v=>sDI9+@9)CSnY-4#BO3_!3P!e0I9L6e_=7GJvda(Uc*#us_I7^?fxv@K}i; zkVeXgDHf*}Q@5MA7?PscVal}DV(9j3K>&jLK+QYl>yXA{?Am{Ditw&N1}^qy70{Mh ziP^dX%k8!6NM=XdQ#<6dtMYCbTVV{xhm1VeiWYZaA+rx>6WnKE@SVR3!xw_j(!GMr z+{x=2J$@f;-rT6w*vvsxh(|GRw}5qJJ^O=4a6RDyUk|bcql1R=XH!jJo+)9Vc zvISfxym+wR4DN~U`FUKnRkPHM^J|X$aC$}EC3{UAXcb|OHq$@2bD#-@1vA=$8l+s|he#A|!m3}Z zd0UJmtQ_@+6I-I&0T#-Jp+G1LgVMKE_h0;p$Xh?@kkkVM@EMM{G}y=N{K^CDSLI14 za8xk0tOGbG^v~;9Q+``(PyCooDI(G+bAIxDg>c}E9oEG;H}Vt|p7e9=13df1b;e`g z2_y6oB#c4=e0XQVo!_;36khNbUKv74j}P z1npL6#hsAXQuJRe^veGpnm)-3=)aC(22Zdhg7I)M3X$doZR8XMufhyf_h{a-HaLGQ;JS>_Jfb>$io2i@uUw^*#YJ z9~=F_38%$j-S7Kl{!p(341r!!{f!ly3(Ukj8Dh6VUf6HxN5EFH>Ib4*)r<$jtdH}2 zv*#gU>O*^pu5RBI>e8*Kazv6E7zrqO#xDti+Ff3~50t}w%LOgiYwtu-4A+UO(<*rXLh%GxD^E5SufsxSC?W zB7rsO^#WrJB6dAM(~=!=o!$j1|2X-cthZ^o?MuQ{aFo2QwYsx*TGfHi`hh9}S+MMEK<~>o7b7QIVTRf-%POB`h8g z-JF6cBg&J?pYNDFcQ%w=Fx+3zzC8F#ciO{S)2c%y~3vT#)0LR8rNBQqUy#Euu9Q%c42^ZHpgYi#AYiy|FgKqUz^0~_o_Fy z$xYT`zGTKygvGyx^IK=}?R8xxU$3q&BgGUmDYOK2ViMSZJLC#ghNVvKVywyd7S|p> zxIWbC!82s=&LWjo(Sz7SnMYCO)ftEwjFjsV(uZc3|MiK5S+dwp8dG3pzfo>Sq>_c(Se`AKR8%q^}N=?YS7m~9nj z$pSo~Ujc>;owB7JED0jK+&>B|VV3R^YND|29l$mxsauZ=&CZFQPVxOC@=mR`tcW$0wv$1bzPbWsdiZfcBJ^y>nPaQL-whFn7(-*3dRs*v z_5cwu#=l4sr`O77e8zdKT(7T{G_dr9b9X#s-NLctZv z4lD@#4V&CMKNex;ny6dB0>#Z!C8xf;KlNB^R?P6QwHA;9OKP-Dw@(&(6g%%umn5Az zS2KQiXA!Wiv6@!ED~&}ye@74gKw4&<-&r@|vwbTjqD5O&8?+h!%% z7do-c0w(j|%p6`b`jYwG|C#?S5QZ(%RV_sc z6-cE?e@|4*wt>)DmT?meqH9J-nVrj&?aP{;Co1&{ARGG^M67>DJY{K3Ef={bm+Lsj z!-nK=2i6fiaXZBI`3k{Wmfx(D*Q}KcN0b(E(Yrji1GjJXK{8BaA#vw#qx75J z%2|_~t!_$6PHK4U)_w}9{dNA?*zF0+`dOyWr$do>DA!Ztx>T^{)Kk3~8i8%3)jMUeiXMK|DE`RHL(P*6 zx1RyP%KnRvkr-}xjUZ*%PBPmru?jclF2X!Q0Rqt<1saEw*GOD+4BV};;asH&-u7kS zY#&=|{?FjYfIir|)NZI{T&HJwZ%B7=7nYTPxxRzD(n!d=k{bD-45)u|K%Vx4p4RWv zc#c--$R8!I2re7;NoK_>%;jOVXl8UQpaZB;sTp1GPPD$}5}@nbgx8{nI#4BI5_jru zDUH%1q7$CMFOCGjV=(Pb9Q!12k~}q3nWhdg1QHf@yb_JTH~b{0FpVKb*~<-XPT&}` z#Qx@4*Nn{H&V5A3Ep$q)O=%=kL{NK+i?dq3h7p^xM2@;QFMvq$tl3LS@#%m_S9kTV zTvyhGocxp$Zqru7Y17sGT_;VxjTX_I*Q4R!79Ld6 z*$tIZWY4#xR3+Hzfw&#vA1(~~EeiSm{>e7=lmSDLQ%M8c55&oYKbNZYhlD5U=|*p9 zh&4~K z82V3@dPIYzR?Pr0-QEjal1m+)1qk$p;(kfFNBoD^UH)4B$LMegfOn%*;pEW7Xp_%zsYde~gAL+8!o)9D1DNLlxlD&8Lk zT30zI!Reob8lr*pf)#>+XUDjW^EA#M21m+;1EU{$M0H9-Fd9(dH8R5_i3tKCd-ov4 z!lctkXn%xLF>Y$uC3rIU%l3Y&#yP5Ye!o3ZjD2c>-alT4YLX%wHzPlz*C+{DiPk3A z^y9z+-z@35H?XCUn4ccN_4m`-whiJ|Ro{_|go@F79$86~Z~i6^YD{Ew*>}(`70las zQg_>)KZ5UBaMz#(!_Q6|@pJg)(RpC6(TQqc_&{KmJ?yo>mC%5`0X|e%khI@V761 zOA-8w{|kD2xQsjRc-1?2Gq7p$*NUI-Pkij)?=`}mt#|^+r8?0XIj}-FV^FwiBUTw! zEa<~oIh!9<+xy!=P=*v1CYB1OG*el`ZZQtm>if|kC})gc@$Ml;jRJod>wB-us8CSV zi5W3**H$+72$q7{jldvV?)tfnp^m>)i1E=4G*aMYY$D<{!=tCva79d`Q$czqL0G8| z4;7Vj-lK_VCc*oxBE@jaxBV4Yjlvz@7avem%f63K*HM9T|hv0Z-QW{BI`EjC=Ea@m8(?he-@9VDN*8Hn{Ikn!8dNk zvD9`S^(?t)XUGTZsGO_f_d>sB(d~YGc8+9&>@T!TV!}KF@ju5X>59FKWI2vYZfyQM z@-B3zw_pRgSL-vkWKyx-AlJ&;R->UgNaQuW+Lnra=S+rf>bD%jUpphR##$~!9lef*?0Z@L?i!zGCAPc5g(ULQ`1;4FH> z2HMsF+_XjzVQhT#5PiHp`f!yjPzO?b-Y{GpnsP=B0nrWJd_E$u4<^qK8Gx zQp#BHy+jpQuLzm}E0-Ij|GtP5T%5dRBGvq$^V8yzvkH?@(413|m{Gpq)OEEKXpMBb zZrL*0i#Q!Hvfq0e6%vKU^EpU209rtwC z!&+Gy1%tUWA$oO|cEu0n7W~)X9+nh}zirFqS(U|sDFX3m9gO8X>0XCSBB!%j=UjHw zW)d82nmj(`9&e)>fn;5O4|&IPez%4A=2ETYN$rx`{kLVh!$LN@M2Sb7nZQMwvfPac zPbn(VPz6Rn(hOC1M43$WEJztyZJcPP=eKzX6aBb69+io?sh*9vMX`IozT0}BAiv3Y9WKtZ zd*ndcegVzSV@lP+MKpRPsw-pJ24Lu^i$=XbBJ18gA zFf$kVl2oIkl~m?gCq4e6DAoz`W=Gp)Syf&M9RsG9#eMWSVNR3Fze|~QdU5N0M}O@xcQ4U{#>x7VoBGyh{f+-Zu#S5? zkkl_C+*`bS@nie)J%UMG-qFm{#kH}~sf`*I{XZ-xvukp#$xEH1Ye)?3D5{*n(|c@e zjId@V!d3Fmz2}V(e)iv%3=RQ8X9CTei5WSug>9%si{RYwcH4RCSbBwI1v3Ov&g{p? z1_={k7mQQci+WB3D|8p%uIuF`1w9F)8UYqj&dgxsWOD@c5jb6om_4y(npXctwv4Tb zF~!!zojI7_iX~V2at2@pZJ#Qd3jWss9`P|1PxzvPSf(zy(ds1YNQEaMNG0A6LS15?oi=iFrna*BD=2ViIk6Wzd**jZ61hja?VgJY`&RhgVZO&%X_=Xa@{s!xCbjJ*5Z>=Dn?7 z3-ajSrhF=4F;8FggL5#fTPhu;cC%Fs{6{JYY@fh>k5Q;jycJ1#s$-rzKe{iZP^y## z5kJvLBbt4>lL)3_f{KZYGW!B@{&6AFrnb&tO~tAB_*Hl;N9QuTd414yyqiVwA)FA0 z+oetH%-d3P<|(7y8E7+&0)RF@SyZf*oM`fpCFo!Cl(FY7$b0hQ%9N7N5B@WkLC^De zFc%w13U8aw%QQb?-hBQ@SiC4Ir7>%5jJB~p{*_9AH0M^|t8p3bA29(DkOK6K$pYVc zJgI{V8s+YiIW?yok-neP5LZ_hPf)B1dTjy}xX)$n z_s#qO4^?n=S|UYtM3XKC$%R<>08bS!Q(-DVXoJwsP@b_o2SZHgsz1kq{X~iqAsL;=sRx*!F=mwHr%qJ|Q&1U<%SeRv@ZKGWBVI2Mg zS)J&w(kpa8w=Bz@@4Iiv=^r$T*0DG<;yt%ke&auln^Lt zq#sj^DTJx*>Fwjw(CUVtFq*$0dJ~j3&V+I7J`+?Tj z9F8&E@gidAtT&(51{4SwiP#K~r64Agp{Wu{H|FEdZ$N*tps`JJPY#+TmE5)*#COMZ z>TZI|Z64ZnN{mrBr}0aT6Vc*73J&p~{M^`bc{bCt?{N0f#JbVv^agI{EiGRx24!Xh z?nf=DC)k&jaqx<~uFpAX-ME(gqmd2=$CJK3C1zmPPC{!;Yg_jYEkEMwe`+mvwMvB} zp>dl|bKXuWXjCvP@)$1{;l;L?nCDf-gPim%~!ANi_M*J1fcTI4aWYvF=7vY^Z`#It1` z$jf*9KY67KLx(CAk^V%o{4O%zZ4IKxY3Z1paUBO!#SqZ4RYBfAqVKz(ozM|`R{kZl zvH+bLk-EBsoV{7wz9c3NoW5$AMBWtH%xEx}y#m_bt5+{Xb*C+BijlrRNpWYt*y#&X zEOO#t27zKq|367UBKrsh^IZSu1y&eYywu zKabKbn44gN9Ssdru(6jrv_Xa}d6Sx@(xMgHM8`>yGb0K)A($qi2HaA3W zX|v;|w_gr%h1#4wL!8{t|+o|HIrW( zX0DEX1-C77mpJp_8qpNXsAyAl8C?ZODeYqmx{=nQk{C9o2{N6HPBv8jrcTe}7ldnG zoWV4YHHOM!s(?ukd_wws7STUl_=}ZDT6XtLL8Oa8i@`S!VGwph5TYh*j^548RWXqp zce6dwEn*M&m~m|<;F%VFV)sO9GsTTVa--;SzcJ>IPZn^x(Nd%QIp3sO$RLXcgk>5} z)vdqhHXggmATDavfWSSH!<706@`SP1LH<%EVzL4sv~hz2@3*18{#Dr$XV+h~nAnrC zohW%w5;3b4pY#+DbbEB%3+m3lLFG--3|mkCi~9qa{5l@S^0C|mL|>HRp|<{*0Fk{U zEvv%PTZ8nY?m}YB;51O}CCvTbPN){nbG(Zj8&Ki5HZAbEAOYRcZH~ialU(>HMbxA2 zXuO2o^ch=EZ-r>aKA4HN)Nbkn+1lrrGS*QcNPBkfEBm==d(KxCMVIJ`1+%w_Z|sm1 zT+$-Uds`yWyqsRGj5?!~s*o|DG~k%e%wj>$WJ3Cd{^hYuMheANv#DHKTspXJ93*xW zb9>LjtEnxW#nEG}!dB9Y!tMCi_T`@T{xsXX&#BJj1cI{>E zbtX*MCqb#T?lE;1#t|_&<7-cbloVG9dn{Sb+0N{3i!BPP z$6xV8<%&gif zuQigrq^e0J5cRIDr@>hC1VxC;(Z>|ZbEbbF=7mXSyqF}3jofUp$ba`a zVgc^Nj61v~L>vB@~;}p~x zDJ$D8U0f@=i&ZS6!u#wLOVxU1=Yc(Nu|@y~y`MORUBzVP1Sd}Og@>88MB-CKjDIfQ zdlPKS0^EePbKR%Yv*1QoeXX{jE#z}P$&#AMPCRUJDoIxgM3oIyOSNsfv=%9U1@={1 zJ~}PSx8OTZDzx;CLW$InLn){VRX6!w-zy=0yUA41e?J!iJFnl1$ZHjMx#%T0x^Kv$ zoLG|X!rkX7B*wHde}G@CrrhR`)M9J?!AApv&)*O*0y4f%_7UzVB>WD=4B<++Fiehn zyS8I#yyh$?-M!x?Mqh}I?r69VU?OC-`}HuJpmk*ML5&ctSiP^sLYI4wEiOJ;8aw zHPK&&+{&RM3vGNA`qqg9se3k(3 zS-ori6`|*H9*Bfr(OSTt0B2RGy++Ys)^o#D^GV8b1?VaoH5%Rz;umT9YhLyUl`=Ws z-f+DPXh$r^nDL_9i+Md=`UHCN%f9Y+jREFIQ;J8li~d1E5rbd60tXL*))fz(77%GP z2x{Rj5m~$Q&(`^k?7mt8(g%d%{2a1+|MJ}Pb(TbHQCY(t+RaUzkxb<#QI9ru)|YPU z77SPoN+YMLF^WQm*(5NI3+j{B`MRyjveuBiT1(6dp<2*-NUWY$V3cm3@C&bgzchkEr7yNNMoQNcsnQb~lMnr^!2Nk-kZs;fhp6R@DWHvZUQzYDM z=dPx!?eGR%>+CQkG-!wBztk$5Wgno$0z z{f)V3_Xkv^Ew|o9SNj>7IpHrFFaHAUE}<264J#51-GJP7gHdyaqYhB3UA`wbbGHU` z5NV|jQlfsY&PYg-8Ykf=(aX18?C!0o8hq!$lCp1$K3qs3noI^ejViqys|o-bi-u-oH?@Q2?vrC!?L@PVR!n(v?K*xqb;JDTGgS*+7$8lX3PdEjnS@cV ziacw&OtTX26!sdfN`GK86~4sceJ^ADOIa(HV7Dp`-J~{R>6!XW-2)4rc!`}W@J${I zFcxHUKF8Zhg34!ZsufVrW%k1^=SqjDq}*ZBkQ`;vIq$S80?r02AuVJQlKwlBW;@^s zAY0pNIGXo9FcwKQz6hs%F*M2e6O5XoHv(&K+s#TxPXJKg{Nkv=3Q$`MICOFN{fR{g z<8^dBT6u$Kqrn|f2;=OK$WfJ9R5X?4&v{b0`J`>>s%zo8xSp#i=BSBfZpbcb*nF5e z^7JDnU%GK^m#DBWqy259qvasfC1~H*kRs%9i(e%Bp3qc_p+ydHr$K{Ym*KRO|D?{WUnc1?R&~!v2$-t%~-OJP67ui>bWEXep zZJF)9ZfMagg4b|HSysC63ZRU^2S7YjxD#rHDcZ=N* z8y`pNs5RGs?o3a{nuKosEm^>;aA@9a-)!q**@E4fEoj9W_bB2yhEgv&DXmIjS4Ria zSj>zWazo^CzoovokUp3Fvzf!yaD|lcvuutQ19xHUj>S)GwwDZ7Icd7;g?$B7l+o6< z2vQOvAR$Od=k(Ae-3Um70}e2BcO#{gh)76DN{e(#Hwa27NC?sm((#Y?{`anXXTIWQXFog6Uh4qIQ!Uh1t!B~CMl!|d&X_c8epA~s;R)E0W$DimNC|#qyxq%<gE2I0Qcy}c8qx`>HISh@geip!yJUU(Js{Uq|^XZJ<}Tv zG66f|^>Fd^rp!5yar;{nt8C9Vd)}9Ys~_T0J;b%VF&VcBy|+&pPeqra-erkGP3jsF z@LxS=T($2#OEV1R7FFzx?_tc5gT0X^?9~5u%}cOKejbjQu3LjFzxnqwSX9MZy}-=aj)ghZfDF7ZQl7lo*7^5 zq5_bApo$XG(b;3xi)Q^{08tmt0rj*Roo+>VOOTiGU7UNoHz`a>>aPMHLG8c4ZsN;F z*ssbq__yR79sg9R6>;gQedRSh(qLgu|GG~wspk1q?Nvi~?odhbwWOj;7}x)J#|seq zju)7a5a?gmxct511@^BO5Hk!U{O{Xez{~(*L3xy&8`6bYP~HyVhLlBGI6gxXOGpsA zy15_`_N2sKKkRkfb*O$!=26f-R+b6hMt?V7-M;%gnC@vLPB=@hk(41G5e_PTJ8^qk zU0RbZ?~&x3@7&JiMD0ZFw&eM{Pdm-$o4ylBq>hVp7Kv$nyHpdi1P)PFOF}S@qLkDP zuFss$NBW87+nKrQZp+|=gecvJL1<=43{n%`#Umyr4B9maeo8Z`r&yORPTY&=IQ6`1 zy@VIsp1z=%_3Gv8mz*=*54e7>t#NOxZMQ`ndJP|2y_O)sm;K%mRO7@+d#9w-qNpg3 zWJz-ZgvZly2f)@zRJe%P!mGux`E37`(36()%fu}rw=>QgKkAsXc3UC!2bcUe7Kk3b zzaso3*C2!or6yfUtg0pndhs*>7jP#e=q6O>%1$9`hW)An0pmI``?+^R>zb9bx3%}o z?9h>V?UMXg2SIRB^hHp^M+8PhIPVcwNHDH~j8lqA>qd-`G$9 z&eQ3c-)ygs7U~ryK$Au)wB@ccaGahJ4ZbZ`l@Jq8)3l7#vKwSeqvFpEZJk?w?Ddo} z%BhH0683+~J1^M@;~tW^H(moVIM!;uoYrd;T{2^fS{@*DcbLddUg4C;DbWKRP&zN< zFDYe5-?jbVHWBspOrg8g^z>Nw10SBe=ywx`>MkB@@QdBnSIsTukBvmbX_ehb$kAKX zQm@bMsH?mim1HgSfe|bIOaM`ly5iD9aT9?GWo~;b{>A0(txtSx1vh%%zgaIH=be87 zQqN6m^7E!y*BX-dYxy}HMCX@4^}soC-pH&+_)hPHKbcX#-r1U3QYz7uyO3XdvQudl zH=D!kBR0pXzRs?5p24G!w6^f?$9-xV2|ElA*+@t~(R~RUQAmozp%jbQyu)+$Ig%uR zRc=_|e5T%XBU;e|>5~^*Y!X(9vHkdqcfdVvP$*WdIX+d&%dwk9xI?R`@NJ{xcJ>$GFG_5Rn^I)&l|HT z(KDZhlGPf34gmn;bWqoj?4WancMk}9}WT)fM5D-A93y3@jgAMrisc-WasJS za#@VF>vj;KIDoMU#t3y~a^C?-c39`r`1rcmza3>?%S$+r;jyOH6PjSyuo@8yY@a$z zuQ=cRJa*Dhok-6dv0W({J8fSZ!Y{hDfG5D z?(YdM6+`RL|A6Nu!LFUhsX~jj(T_)=QXlPztG{%Lo@j~0BBu;i1ww&STXnl~Nz z@b>-40rqU%C6h!*y$05ZNFC0mbdVli5x4l=IKJzpsJG2VSqs!@anuIwl7e+|e-3Hk z-!Fe#?m^i#rrwaiX3v+rsNhk@5mzBUk{T+dl|CGeG^hxF$BBZZ8SS=@t>5n|^4b-c z9=JV_E+_?&uStU7YSEx87Y#hKvLAU^O1Qcw=Ok;Z5GkW+f)$zCD>N64~4aA-1W+ z=?;Vo!osmfPnT4;vRa;q>r>xZc=AzL`Ukb|A)1#(O(48}Dhi@X)U9*6pPnuaFSBua zA7+v($qgwQv(ZA^Sk(O3e)yc4a**vk3{{obNGt@AXw&!GCU4wz;#Iiz)t6A|qi;gV zH11N}qUHsZgfoe?GX0sdNjrQOH*DZ80@S|~wy zeqlFCHu~MN^&ufAQyry1u>Wh*R;hGFWr4)LWEaDlKub#4>Vd+8`=!f6TtxF_3Kj$O zx8tKdw6g8J2enj=3@ul=YRB8tI$khF^hG>1qyR3<`)Sgh%I&Li$yFC~bN*CJuL#va zQ0(vhsV%giU|+qbL3?|EV`X%7UYBGby)Y&?lCER+#bzTV!PqC$cThb9avbceN|0vf z;K9@V_=&08&oK9UJ2Owle;j&CdyG{%(G3K1926GK?d_dL0 z3R}M)>rbniXCnF)>N-|(3UHH1HubiM-(=vm<9*ezo_bdFRf&m97ra(L_1uba7qr+6 z?k#*Hohp_`Oq&^adC!kRBCHj7}g@ypb^)C^VZPyB=HMnC_@=15GHL6x8SurTlx zI*Nc$44g)?8Mz>JhV@qy^ehX6qKN0&^jUs^o={6Zp=wJ!{>A^|p{e1ru_>T-Z1E`B z)wtL@+1yo)_)7Dw+->4pRn9T~q`L*~qh_asXU$DnBx-@F8!4i%681%^D#RVjM!uEW zF`887)n!*H9)B%owj7_$)goTj1#0qEeZ+r9coF%;RFpuS950B*%9-w)J>;aTdV6I z7wLPHHELN-6P2jy=~%ZdXDM2Sm9JIP6l%X$LT*283OMVC;kxB?_ifmhwTS*ou}nbh z!b>>Pg#cmFvNhlpvvuIy-|~jS&0}oPP(*g3Q*g8iG;Wb`ds5uNg-y8)An;bG>|8BX zdu)E(A`hxOwnM|ss^^;~=1Q!DTK4Kw@VOLE6qZ=Xn0Sug*sWK3;j7TwAP#(&S8b4V ziMXIxqy^{SuA!EriQi!ybyH7>bv>MXD#@_?1=Tk08eurgg8!E3y>NhtPz3!??qQAe z@{94RVs`>SeZSEVZTH3A*5`YFinxO(49j94YkGH}!g4{so{@z;x=P7MSpbRXx;!RA zxT|LRG)dpnhlk)B3xw$762%gD@63kf#?tbHMCR}Gp|pw)S$Z;?a-p|IE87{)VI;t*eyW)gxJIAMH+>g8O@$i=5e46i#gWf<*!)uGH{GAe1 zpNE!He%=zh_P`?xuJRu5T_m}h-F9ZBk}x`sHTg_q&$UAcZXdby+s&?|)BOU7)YL!u znWKtiF(9E$BlU1Wy@)xOUeFT9sc$_qv@$q#`8YNG(_CYZLGNeHmUlzi+bhWK2;tqkd=l zY)F=QeO&`DzS;(LXA-* zH7>~vmHD$nLl+$BL6}$zL`ttTv5x*!1M^ew?+F2@p9xQ*LW9{*u>fJ*o5eJmJF+dh%W= zZ|CHZd#k`xvx)%@dIgw4;s6(wgtcy6uBv2`AYE722k;|BQ-yMZg8iH$SZVKv-wS@O9sNNx;coB{Q{@wzOwK1L>BtXv!C&@L^ zWJ^h`4BKZxb>Kt8zHI~a9UoNj|)-3G-E zvRb~XJ@)b+MAh;#rdIWplFkKMn-|t%*%b&0?!85=#x_i9D6+%C)s# z7~*QCUPSi?SC41gd3NuJNk}uSWM-JXdR%N#-u|#rI)UP}<=AFyxW3-_-VDk{WsQ)z zm#Mho{9d|G=fD0A~` z=0c07`*F&RPl6SB``x*>C#s@?Pt4?P+jy$Az%6jQf?DS3ed+_7P~C>}jMzpN<25}I z&y@TNf2xvAjes~smwVEO#D}do?YF0ST2YABo+~2hW*1>U@@~(n!=Ec0Fdd=K*ReTzo)9{^{ywuN}oQ-0|iqB+a7WJD- zyU~EbGPQP;YWzO0ckF?dlVB?wG&a9nWV5SrBK}rLw{oa=ha!G`a(wjUuxd+HBfh*= zh7A9JjBAFm1NewPE?oUFPqH!Z=W<6;^%Y_gD9@jNmIGI+e9+*)4J~~mCM{~-taS@$m=|`-d{FM91-;jyLm86e-dA>IR0LAexO*j zxNmww%8x0ZKZm=|pF`QUmg!4w3HyEO%=MWY9Tx=xJ5gW43R5NYdA@Da2Ru%!?kTsd zzBRsP??f1TNcd?}8iyqTeDQ5mmHtc(Z(NR|_?;&u&}2NXh>`=BV`dOQy63%Yz^PSeW8pyI8Y##lqge}UNh5pfpyMuzFz$%?lUprjw4O^|~ zj0tJ02M^!8`Ygr{CzNtGzO4Fov7b?8?C0mU86tZ;`}Lyo>wJ%1e+u<_+=`VlkH+pq zB;j+3f*1#s0XYrMng!e@u$NGLU@m^E|LGmvW#o|HOEE)NUp%=+_{R4apNj88qfB@U zulQwW=Nwol#eEc?2M^oi_&BrpVx#m-kwy-ZPKrL}Br9_P#6`k+`AFXHNWxJ=&C zEN~;a%b4`UD*v%~XUq6keg1Y|;4{7$XV&JI_$gtb)n7~Hq~?yyp-sP@-9v+8Bc9!~ zW6C@H#7-v~t|b9jS0hWcii!8DS2TEbr-;)UL5z&ybA0RjzU6z0Y1A{0Xn)^Vs=B2f zWz8IRqMjExJ$8BTqd$fO=t=1lbCz>QMy!0=^1j`@=OKbHtuP;$Ol!lXd=1+U%9+)s z?~?FaR?UCBd==GOjMr>6Jfqk~RZrG6@5IW2I<>X7Qp`S&pv(*}E^}60tZ28Sesr*H zQs_7_mUid055Ikp){8s6Bby(#9ucM{`=rn%9lpQeq08s_+Tu`El8p*lbhha~qvG{(*uYJ-^Y@$E&QvIW~Omn%Bu%Cfr`C z&!^WV>hiu*y|diseWYZ5mQsDeF@g9lJS6&VW)5}bvFw*2OJugPYxB@%8vnr4(k7Jr z7fIh2KK*qRb@I+*c}6)V)SbB~+4$Uqo;wEo>Jt>nPx|mVWC)bkaa$=ZVcB81Z2pW^ za9pzLiw9>38v}i-!iOkSN>L;r~&{HQ1&d|>GobLgkeu^FjS z4EXUz!Apnkx7jy5shLyd5858@OK;w)ulre(9mGpb?QQk$pySIT2#LcYW!^j8K5+zz zV&{e-mYQZ9J4_RSKYjL2_@5k^*_oyrTQoo>k%imn!b)*UHJ=I^f zU^LwEf_?N1`tsVFKBfLDRZ~Pq{z!@Cd~HLF(&*s}d}3vty>5kF9~i43yTQ_vhD$X?Lq(D(#cc)Ga{wY)|oeUa^B5&N-`qKyY!% zmr8^Ox8ekFE#+?04H=f!js@Zo^u?OY@m~A>Vg4JpQHo zd5;p6eeVVak-folY=ZTy?pW7n)8SFt8g)EHboE~91)L|T9aS6~SS^^}Iy1_zrxpf?N5U-uUkBZGG05C$q@#P^nCob zp?PxFFvWJh!Kfq4YGKLzeI;yAg3GvnsJT$Jsc=j*veSa`?HV8Z+bWt((z4f#IRf(& zXBP&+%)-KZF;JQ>c_fVR$Q^cDBO9O^mo}dD1u1W}u62cI`rJ@C`DBuFT->?g<4}}f%Y1gjgPnMe>_wJ{l}r2HnX6DqmCo7pe!?&tGl@?(!vep=pXY&{0kjz|)j-JeJj?A7eC^sat8p6#QX^(J2 zS-5f&3raHsfl%~_$Han~2p6P-8~XkKzPcbin1%n&hW?p4(#wrm_@9dZxftX>7W-cT zLjN1!-&y_z@P8cx`Oh(4E=Wsa02&#L81V0h83u)dq0E+~|CaqVC;(Fih5TjlzxAL{2-dn#n6NOG9$W}}K4Bo5 z>HnS&1^{5mgn$4zrk)TO%@W2~A&3wb79kh}(>5Ub!Ni9SFc`KB3d0@?2cd)Kzc8a` zgJIeR1OcI#b^t*jv==ePfVe*i&XFs2VUfngXij;)Gznw! z2Lhr=z_1Mj0)jAY1A(w(0|bI$)@*dC69Qpj24mInzoib2$ukHH!^#Epve@>bw~1J|Q?5fDz9ifH3@T zL-L<{3J3&;3uE{f1QLc~#sQiZ0A}u^cM7b%2LuJdfEafC^%@w%=OCC6NC*=P916zF zOZ1Kc!OUqeKnQ|~<*y90o}y(?%-l!IVE-ArZY~Iv9n$5W-JZ7-l37syF}hh2RC0KR z^kOzbH%$<*39+Cy$_M$6{z*`e*$BuCW(J~#j~yM+?cP5dJS7K9M`pB*f15oeS!N?K zG#)t+Tm~Qqk(C2TL*eM{0|s~`BLkC`m5~R+;S$XMe--o^sz?VbH*01v6#W1A9WR87 U+do>ozsA8K#O&;H8uG;d2iLx9wg3PC literal 0 HcmV?d00001 diff --git a/src/test/resources/org/jabref/logic/xmp/empty_metadata.pdf b/src/test/resources/org/jabref/logic/xmp/empty_metadata.pdf new file mode 100644 index 0000000000000000000000000000000000000000..c3b88c77ce149f6c8c92d3c1e989cc62474411c1 GIT binary patch literal 292231 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�d{gprG@OgSA!l|4BZr1~M2$=9Z{p6*rOjlx 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%0AN%m~Afk}>j!B~gh)!TU1 z+GeFu+8P;T%xA4YZ(MK9Wzo3bFOlLj9`p2P&Y0lgrl678JkZcdsXa@+3Uo>Px51?EUY3$-~nM Y>gfZYOR#u>Jc7L3Sa06QX~<*!2e@ov@c;k- literal 0 HcmV?d00001 From 12342a2910102b4fc9cfc95c5bb00030957c367c Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Tue, 20 Feb 2018 22:49:35 +0100 Subject: [PATCH 83/94] Include desktop, desktop-legacy, wayland in snapcraft.yaml --- snapcraft.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/snapcraft.yaml b/snapcraft.yaml index 7efc6989c07..91755190c85 100644 --- a/snapcraft.yaml +++ b/snapcraft.yaml @@ -2,8 +2,8 @@ name: jabref -# the version string 4.0-dev is replaced by scripts/run-snapcraft.sh with the current version provided in build.gradle -version: '4.0-dev' +# the version string 4.2-dev is replaced by scripts/run-snapcraft.sh with the current version provided in build.gradle +version: '4.2-dev' summary: Bibliography manager icon: buildres/snapcraft/JabRef-icon-256.png @@ -21,8 +21,8 @@ confinement: strict apps: jabref: - command: desktop-launch java -jar $SNAP/jar/JabRef-4.0-dev.jar - plugs: [home, network-bind, x11] + command: desktop-launch java -jar $SNAP/jar/JabRef-4.2-dev.jar + plugs: [desktop, desktop-legacy, wayland, home, network-bind, x11] desktop: ../buildres/snapcraft/jabref.desktop parts: From 667525afe3d36ea1636ce814aa81c2d702e009b9 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Tue, 20 Feb 2018 22:51:17 +0100 Subject: [PATCH 84/94] Replace x11 by unity7 [ci skip] --- snapcraft.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/snapcraft.yaml b/snapcraft.yaml index 91755190c85..0daa48c83c4 100644 --- a/snapcraft.yaml +++ b/snapcraft.yaml @@ -22,7 +22,7 @@ confinement: strict apps: jabref: command: desktop-launch java -jar $SNAP/jar/JabRef-4.2-dev.jar - plugs: [desktop, desktop-legacy, wayland, home, network-bind, x11] + plugs: [desktop, desktop-legacy, wayland, unity7, home, network-bind] desktop: ../buildres/snapcraft/jabref.desktop parts: From d6fc974cbb7f5f6218de2e8313c31697c37348f9 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Wed, 21 Feb 2018 09:02:13 +0100 Subject: [PATCH 85/94] Reorder checklist in PR template and add "good commit message" --- .github/PULL_REQUEST_TEMPLATE.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 7abcfd623b6..4ac0bc29d94 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -5,8 +5,9 @@ ---- -- [ ] Change in CHANGELOG.md described -- [ ] Tests created for changes -- [ ] Screenshots added (for bigger UI changes) - [ ] Manually tested changed features in running JabRef +- [ ] Screenshots added in PR description (for bigger UI changes) +- [ ] Tests created for changes +- [ ] Change in CHANGELOG.md described +- [ ] Ensured that [the git commit message is a good one](https://github.com/joelparkerhenderson/git_commit_message) - [ ] Check documentation status (Issue created for outdated help page at [help.jabref.org](https://github.com/JabRef/help.jabref.org/issues)?) From 7647f02572bd4430b68d36fbfec1d61bccd2208e Mon Sep 17 00:00:00 2001 From: Linus Dietz Date: Wed, 21 Feb 2018 17:06:00 +0100 Subject: [PATCH 86/94] Fix logic --- .../gui/importer/actions/MergeReviewIntoCommentAction.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jabref/gui/importer/actions/MergeReviewIntoCommentAction.java b/src/main/java/org/jabref/gui/importer/actions/MergeReviewIntoCommentAction.java index 71b52e42eaf..c1aa6a96b74 100644 --- a/src/main/java/org/jabref/gui/importer/actions/MergeReviewIntoCommentAction.java +++ b/src/main/java/org/jabref/gui/importer/actions/MergeReviewIntoCommentAction.java @@ -20,7 +20,7 @@ public void performAction(BasePanel basePanel, ParserResult parserResult) { migration.performMigration(parserResult); List conflicts = MergeReviewIntoCommentMigration.collectConflicts(parserResult); - if (new MergeReviewIntoCommentConfirmationDialog(basePanel).askUserForMerge(conflicts)) { + if (!conflicts.isEmpty() && new MergeReviewIntoCommentConfirmationDialog(basePanel).askUserForMerge(conflicts)) { migration.performConflictingMigration(parserResult); } } From c0677b3d653c3a86db0e99a12979cbd2b89124e9 Mon Sep 17 00:00:00 2001 From: Linus Dietz Date: Wed, 21 Feb 2018 17:09:48 +0100 Subject: [PATCH 87/94] Rename confirmation into "Merge fields" --- .../actions/MergeReviewIntoCommentConfirmationDialog.java | 5 +++-- src/main/resources/l10n/JabRef_en.properties | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jabref/gui/importer/actions/MergeReviewIntoCommentConfirmationDialog.java b/src/main/java/org/jabref/gui/importer/actions/MergeReviewIntoCommentConfirmationDialog.java index 4a7eaedd8f0..b6db65c716b 100644 --- a/src/main/java/org/jabref/gui/importer/actions/MergeReviewIntoCommentConfirmationDialog.java +++ b/src/main/java/org/jabref/gui/importer/actions/MergeReviewIntoCommentConfirmationDialog.java @@ -25,13 +25,14 @@ public boolean askUserForMerge(List conflicts) { .map(Optional::get) .collect(Collectors.joining(",\n")); - int answer = JOptionPane.showConfirmDialog( + String[] options = {Localization.lang("Merge fields")}; + int answer = JOptionPane.showOptionDialog( panel, bibKeys + " " + Localization.lang("has/have both a 'Comment' and a 'Review' field.") + "\n" + Localization.lang("Since the 'Review' field was deprecated in JabRef 4.2, these two fields are about to be merged into the 'Comment' field.") + "\n" + Localization.lang("The conflicting fields of these entries will be merged into the 'Comment' field."), - Localization.lang("Review Field Migration"), JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE); + Localization.lang("Review Field Migration"), JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE, null, options, options[0]); return 0 == answer; } diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties index 6b4b8ea1d3d..cc23c0e41a1 100644 --- a/src/main/resources/l10n/JabRef_en.properties +++ b/src/main/resources/l10n/JabRef_en.properties @@ -719,6 +719,7 @@ Memory\ stick\ mode=Memory stick mode Menu\ and\ label\ font\ size=Menu and label font size Merged\ external\ changes=Merged external changes +Merge\ fields=Merge fields Messages=Messages From ab2cbbbead151232d994f10dfab61f61afd57870 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Wed, 21 Feb 2018 19:10:09 +0100 Subject: [PATCH 88/94] Reorder again --- .github/PULL_REQUEST_TEMPLATE.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 4ac0bc29d94..9964ff946df 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -5,9 +5,9 @@ ---- +- [ ] Change in CHANGELOG.md described +- [ ] Tests created for changes - [ ] Manually tested changed features in running JabRef - [ ] Screenshots added in PR description (for bigger UI changes) -- [ ] Tests created for changes -- [ ] Change in CHANGELOG.md described - [ ] Ensured that [the git commit message is a good one](https://github.com/joelparkerhenderson/git_commit_message) - [ ] Check documentation status (Issue created for outdated help page at [help.jabref.org](https://github.com/JabRef/help.jabref.org/issues)?) From 58c2c7aa941744d9341454bfb5eeabeed77ab54e Mon Sep 17 00:00:00 2001 From: Linus Dietz Date: Wed, 21 Feb 2018 22:23:48 +0100 Subject: [PATCH 89/94] Don't trim when migrating review field (#3761) Co-authored-by: Oliver Kopp --- .../jabref/logic/bibtex/FieldContentParser.java | 1 + ...MergeReviewIntoCommentActionMigrationTest.java | 15 +++++++++++++++ src/test/java/org/jabref/testutils/TestUtils.java | 8 +------- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/jabref/logic/bibtex/FieldContentParser.java b/src/main/java/org/jabref/logic/bibtex/FieldContentParser.java index 43c05b1a2fd..e2c3b09223b 100644 --- a/src/main/java/org/jabref/logic/bibtex/FieldContentParser.java +++ b/src/main/java/org/jabref/logic/bibtex/FieldContentParser.java @@ -28,6 +28,7 @@ public FieldContentParser(FieldContentParserPreferences prefs) { multiLineFields = new HashSet<>(); // the following two are also coded in org.jabref.logic.bibtex.LatexFieldFormatter.format(String, String) multiLineFields.add(FieldName.ABSTRACT); + multiLineFields.add(FieldName.COMMENT); multiLineFields.add(FieldName.REVIEW); // the file field should not be formatted, therefore we treat it as a multi line field multiLineFields.addAll(prefs.getNonWrappableFields()); diff --git a/src/test/java/org/jabref/logic/importer/migrations/MergeReviewIntoCommentActionMigrationTest.java b/src/test/java/org/jabref/logic/importer/migrations/MergeReviewIntoCommentActionMigrationTest.java index 2e9f09c2350..f533cdada39 100644 --- a/src/test/java/org/jabref/logic/importer/migrations/MergeReviewIntoCommentActionMigrationTest.java +++ b/src/test/java/org/jabref/logic/importer/migrations/MergeReviewIntoCommentActionMigrationTest.java @@ -57,6 +57,21 @@ public void commentField() { assertEquals(entry, actualParserResult.getDatabase().getEntryByKey("Entry1").get()); } + @Test + public void multiLineReviewField() { + String commentString = "My Review\n\nSecond Paragraph\n\nThird Paragraph"; + + BibEntry actualEntry = createMinimalBibEntry(); + actualEntry.setField(FieldName.REVIEW, commentString); + ParserResult actualParserResult = new ParserResult(Collections.singletonList(actualEntry)); + + BibEntry expectedEntry = createMinimalBibEntry(); + expectedEntry.setField(FieldName.COMMENT, commentString); + + action.performMigration(actualParserResult); + + assertEquals(expectedEntry, actualParserResult.getDatabase().getEntryByKey("Entry1").get()); + } @Test @Disabled("Re-enable if the MergeReviewIntoCommentMigration.mergeCommentFieldIfPresent() does not block and wait for user input.") diff --git a/src/test/java/org/jabref/testutils/TestUtils.java b/src/test/java/org/jabref/testutils/TestUtils.java index e0bf7b650b9..7e6c30c3f34 100644 --- a/src/test/java/org/jabref/testutils/TestUtils.java +++ b/src/test/java/org/jabref/testutils/TestUtils.java @@ -3,15 +3,9 @@ import org.jabref.JabRefGUI; import org.jabref.JabRefMain; -/** - * UtilsClass for UnitTests. - * - * @author kahlert, cordes - */ public class TestUtils { - public static final String PATH_TO_TEST_BIBTEX = "src/test/resources/org/jabref/bibtexFiles/test.bib"; - + private static final String PATH_TO_TEST_BIBTEX = "src/test/resources/org/jabref/bibtexFiles/test.bib"; /** * Initialize JabRef. Can be cleaned up with From 71fcea568fa35ac9da131e0cb85f5bb0e3614628 Mon Sep 17 00:00:00 2001 From: gerzmasn Date: Thu, 22 Feb 2018 10:51:03 +0100 Subject: [PATCH 90/94] Added to the Import File Filter Dialog. --- CHANGELOG.md | 1 + src/main/java/org/jabref/gui/importer/ImportFormats.java | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 547db4d3e80..58f47ef5dbf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ We refer to [GitHub issues](https://github.com/JabRef/jabref/issues) by using `# ## [Unreleased] ### Changed +- Added "*.*" (any file type) to the Import File Filter Dialog. [#3757] (https://github.com/JabRef/jabref/issues/3757) - Abbreviate journal names functionality is now running parallel, increasing performance significantly. [#2831] (https://github.com/JabRef/jabref/issues/2831) - Changed order of items in context menu [#298] (https://github.com/koppor/jabref/issues/298) - Changed ID-based entry generator to store the last used fetcher. [#2796] (https://github.com/JabRef/jabref/issues/2796) diff --git a/src/main/java/org/jabref/gui/importer/ImportFormats.java b/src/main/java/org/jabref/gui/importer/ImportFormats.java index 52cb07fea3f..153174bb00d 100644 --- a/src/main/java/org/jabref/gui/importer/ImportFormats.java +++ b/src/main/java/org/jabref/gui/importer/ImportFormats.java @@ -67,12 +67,12 @@ public void actionPerformed(ActionEvent e) { List extensions = importers.stream().map(Importer::getFileType) .collect(Collectors.toList()); FileChooser.ExtensionFilter allImports = FileFilterConverter.forAllImporters(importers); - FileDialogConfiguration fileDialogConfiguration = new FileDialogConfiguration.Builder() .addExtensionFilter(allImports) .addExtensionFilters(extensions) .withInitialDirectory(Globals.prefs.get(JabRefPreferences.IMPORT_WORKING_DIRECTORY)) .build(); + fileDialogConfiguration.getExtensionFilters().add(new FileChooser.ExtensionFilter("Any file", "*.*")); DialogService dialogService = new FXDialogService(); DefaultTaskExecutor.runInJavaFXThread(() -> { dialogService.showFileOpenDialog(fileDialogConfiguration) From 06b69050b89b4751159257272a247ebc2886b848 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Lenhard?= Date: Fri, 23 Feb 2018 14:05:00 +0100 Subject: [PATCH 91/94] Update Architecture Tests to catch static imports (#3766) * Switch to JUnit5 and also analyze static imports * Use static import for assertEquals --- .../org/jabref/architecture/MainArchitectureTests.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/test/java/org/jabref/architecture/MainArchitectureTests.java b/src/test/java/org/jabref/architecture/MainArchitectureTests.java index 6b6c95ab462..6d4dc2bcede 100644 --- a/src/test/java/org/jabref/architecture/MainArchitectureTests.java +++ b/src/test/java/org/jabref/architecture/MainArchitectureTests.java @@ -14,12 +14,13 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import org.junit.Assert; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; +import static org.junit.jupiter.api.Assertions.assertEquals; + public class MainArchitectureTests { public static final String CLASS_ORG_JABREF_GLOBALS = "org.jabref.Globals"; @@ -78,7 +79,8 @@ public static Stream getPackages() { @ParameterizedTest(name = "{index} -- is {0} independent of {1}?") @MethodSource("getPackages") public void firstPackageIsIndependentOfSecondPackage(String firstPackage, String secondPackage) throws IOException { - Predicate isExceptionPackage = (s) -> s.startsWith("import " + secondPackage) + Predicate isExceptionPackage = (s) -> (s.startsWith("import " + secondPackage) + || s.startsWith("import static " + secondPackage)) && exceptions.getOrDefault(firstPackage, Collections.emptyList()) .stream() .noneMatch(exception -> s.startsWith("import " + exception)); @@ -104,8 +106,7 @@ public void firstPackageIsIndependentOfSecondPackage(String firstPackage, String }) .collect(Collectors.toList()); - Assert.assertEquals("The following classes are not allowed to depend on " + secondPackage, - Collections.emptyList(), files); + assertEquals(Collections.emptyList(), files, "The following classes are not allowed to depend on " + secondPackage); } } } From 576588ae8f72d39134f479e9d6e19def42abddca Mon Sep 17 00:00:00 2001 From: Christoph Date: Fri, 23 Feb 2018 17:08:20 +0100 Subject: [PATCH 92/94] Add Localization --- src/main/java/org/jabref/gui/importer/ImportFormats.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jabref/gui/importer/ImportFormats.java b/src/main/java/org/jabref/gui/importer/ImportFormats.java index 153174bb00d..e755e136886 100644 --- a/src/main/java/org/jabref/gui/importer/ImportFormats.java +++ b/src/main/java/org/jabref/gui/importer/ImportFormats.java @@ -72,7 +72,7 @@ public void actionPerformed(ActionEvent e) { .addExtensionFilters(extensions) .withInitialDirectory(Globals.prefs.get(JabRefPreferences.IMPORT_WORKING_DIRECTORY)) .build(); - fileDialogConfiguration.getExtensionFilters().add(new FileChooser.ExtensionFilter("Any file", "*.*")); + fileDialogConfiguration.getExtensionFilters().add(new FileChooser.ExtensionFilter(Localization.lang("Any file"), "*.*")); DialogService dialogService = new FXDialogService(); DefaultTaskExecutor.runInJavaFXThread(() -> { dialogService.showFileOpenDialog(fileDialogConfiguration) From 4ddd90a6727ed1d2b1ee2d79faf313a876de9be4 Mon Sep 17 00:00:00 2001 From: Johannes Manner Date: Fri, 23 Feb 2018 17:16:09 +0100 Subject: [PATCH 93/94] Refactor dublin core utility (#3756) * Refactored dublin core utility The tool is now implemented as a console application with a read-evaluate-print cycle. * CLI -xmp integration Integrated the xmp functionality in the CLI infrastructure * CLI - shutdown after using console application System.exit() because Platform.exit() does not work in this case. * Update changelog.md --- CHANGELOG.md | 2 + .../org/jabref/cli/ArgumentProcessor.java | 5 + src/main/java/org/jabref/cli/JabRefCLI.java | 9 + src/main/java/org/jabref/cli/XMPUtilMain.java | 176 ------------------ src/main/java/org/jabref/cli/XmpUtilMain.java | 129 +++++++++++++ 5 files changed, 145 insertions(+), 176 deletions(-) delete mode 100644 src/main/java/org/jabref/cli/XMPUtilMain.java create mode 100644 src/main/java/org/jabref/cli/XmpUtilMain.java diff --git a/CHANGELOG.md b/CHANGELOG.md index fd1931b39e3..d4c42cba149 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,6 +36,8 @@ The new default removes the linked file from the entry instead of deleting the f - The magnifier icon at the search shows the [search mode](https://help.jabref.org/en/Search#search-modes) again. [#3535](https://github.com/JabRef/jabref/issues/3535) - We added a new cleanup operation that replaces ligatures with their expanded form. [#3613](https://github.com/JabRef/jabref/issues/3613) - Pressing ESC while searching will clear the search field and select the first entry, if available, in the table. [koppor#293](https://github.com/koppor/jabref/issues/293) +- We changed the metadata reading and writing. DublinCore is now the only metadata format, JabRef supports. (https://github.com/JabRef/jabref/pull/3710) +- We added another CLI functionality for reading and writing metadata to pdfs. (see https://github.com/JabRef/jabref/pull/3756 and see http://help.jabref.org/en/CommandLine) ### Fixed - We fixed several performance problems with the management of journal abbreviations [#3323](https://github.com/JabRef/jabref/issues/3323) diff --git a/src/main/java/org/jabref/cli/ArgumentProcessor.java b/src/main/java/org/jabref/cli/ArgumentProcessor.java index b5579040cbe..cd4e96ce523 100644 --- a/src/main/java/org/jabref/cli/ArgumentProcessor.java +++ b/src/main/java/org/jabref/cli/ArgumentProcessor.java @@ -223,6 +223,11 @@ private List processArguments() { doAuxImport(loaded); } + if (cli.isXmpFacilities()) { + XmpUtilMain.executeXmpConsoleApplicaton(); + System.exit(0); + } + return loaded; } diff --git a/src/main/java/org/jabref/cli/JabRefCLI.java b/src/main/java/org/jabref/cli/JabRefCLI.java index f427c8e0dbb..e6585516889 100644 --- a/src/main/java/org/jabref/cli/JabRefCLI.java +++ b/src/main/java/org/jabref/cli/JabRefCLI.java @@ -140,6 +140,10 @@ public String getExportMatches() { return cl.getOptionValue("exportMatches"); } + public boolean isXmpFacilities() { + return cl.hasOption("readAndWriteXmpMetadata"); + } + public boolean isGenerateBibtexKeys() { return cl.hasOption("generateBibtexKeys"); } public boolean isAutomaticallySetFileLinks() { return cl.hasOption("automaticallySetFileLinks"); } @@ -232,6 +236,11 @@ private Options getOptions() { desc(Localization.lang("Automatically set file links")). build()); + options.addOption(Option.builder("xmp"). + longOpt("readAndWriteXmpMetadata"). + desc("Read and write xmp metadata from/to pdf files"). + build()); + return options; } diff --git a/src/main/java/org/jabref/cli/XMPUtilMain.java b/src/main/java/org/jabref/cli/XMPUtilMain.java deleted file mode 100644 index 430c49541bd..00000000000 --- a/src/main/java/org/jabref/cli/XMPUtilMain.java +++ /dev/null @@ -1,176 +0,0 @@ -package org.jabref.cli; - -import java.io.FileReader; -import java.io.IOException; -import java.io.StringWriter; -import java.nio.file.Paths; -import java.util.Collection; -import java.util.List; -import java.util.Optional; - -import javax.xml.transform.TransformerException; - -import org.jabref.Globals; -import org.jabref.logic.bibtex.BibEntryWriter; -import org.jabref.logic.bibtex.LatexFieldFormatter; -import org.jabref.logic.importer.ImportFormatPreferences; -import org.jabref.logic.importer.ParserResult; -import org.jabref.logic.importer.fileformat.BibtexParser; -import org.jabref.logic.xmp.XmpPreferences; -import org.jabref.logic.xmp.XmpUtilReader; -import org.jabref.logic.xmp.XmpUtilWriter; -import org.jabref.model.database.BibDatabaseMode; -import org.jabref.model.entry.BibEntry; -import org.jabref.preferences.JabRefPreferences; - -import org.apache.xmpbox.XMPMetadata; -import org.apache.xmpbox.xml.XmpSerializer; - -public class XMPUtilMain { - - private XMPUtilMain() { - } - - /** - * Command-line tool for working with XMP-data. - * - * Read or write XMP-metadata from or to pdf file. - * - * Usage: - *

- *
Read from PDF and print as bibtex:
- *
xmpUtil PDF
- *
Read from PDF and print raw XMP:
- *
xmpUtil -x PDF
- *
Write the entry in BIB given by KEY to the PDF:
- *
xmpUtil KEY BIB PDF
- *
Write all entries in BIB to the PDF:
- *
xmpUtil BIB PDF
- *
- * - * @param args - * Command line strings passed to utility. - * @throws IOException - * If any of the given files could not be read or written. - * @throws TransformerException - * If the given BibEntry is malformed. - */ - public static void main(String[] args) throws IOException, TransformerException { - - // Don't forget to initialize the preferences - if (Globals.prefs == null) { - Globals.prefs = JabRefPreferences.getInstance(); - } - - XmpPreferences xmpPreferences = Globals.prefs.getXMPPreferences(); - ImportFormatPreferences importFormatPreferences = Globals.prefs.getImportFormatPreferences(); - - int argsLength = args.length; - if (argsLength == 0) { - usage(); - } else if (argsLength == 1) { - if (args[0].endsWith(".pdf")) { - // Read from pdf and write as BibTex - List l = XmpUtilReader.readXmp(args[0], xmpPreferences); - - BibEntryWriter bibtexEntryWriter = new BibEntryWriter( - new LatexFieldFormatter(Globals.prefs.getLatexFieldFormatterPreferences()), false); - - for (BibEntry entry : l) { - StringWriter sw = new StringWriter(); - bibtexEntryWriter.write(entry, sw, BibDatabaseMode.BIBTEX); - System.out.println(sw.getBuffer()); - } - - } else if (args[0].endsWith(".bib")) { - // Read from BIB and write as XMP - try (FileReader fr = new FileReader(args[0])) { - ParserResult result = new BibtexParser(importFormatPreferences, Globals.getFileUpdateMonitor()).parse(fr); - Collection entries = result.getDatabase().getEntries(); - - if (entries.isEmpty()) { - System.err.println("Could not find BibEntry in " + args[0]); - } - } - } else { - usage(); - } - } else if (argsLength == 2) { - if ("-x".equals(args[0]) && args[1].endsWith(".pdf")) { - // Read from pdf and write as BibTex - List meta = XmpUtilReader.readRawXmp(Paths.get(args[1])); - - if (!meta.isEmpty()) { - XmpSerializer serializer = new XmpSerializer(); - serializer.serialize(meta.get(0), System.out, true); - } else { - System.err.println("The given pdf does not contain any XMP-metadata."); - } - return; - } - - if (args[0].endsWith(".bib") && args[1].endsWith(".pdf")) { - try (FileReader reader = new FileReader(args[0])) { - ParserResult result = new BibtexParser(importFormatPreferences, Globals.getFileUpdateMonitor()).parse(reader); - - List entries = result.getDatabase().getEntries(); - - if (entries.isEmpty()) { - System.err.println("Could not find BibEntry in " + args[0]); - } else { - XmpUtilWriter.writeXmp(Paths.get(args[1]), entries, result.getDatabase(), xmpPreferences); - System.out.println("XMP written."); - } - } - return; - } - - usage(); - } else if (argsLength == 3) { - if (!args[1].endsWith(".bib") && !args[2].endsWith(".pdf")) { - usage(); - return; - } - - try (FileReader reader = new FileReader(args[1])) { - ParserResult result = new BibtexParser(importFormatPreferences, Globals.getFileUpdateMonitor()).parse(reader); - - Optional bibEntry = result.getDatabase().getEntryByKey(args[0]); - - if (bibEntry.isPresent()) { - XmpUtilWriter.writeXmp(Paths.get(args[2]), bibEntry.get(), result.getDatabase(), xmpPreferences); - - System.out.println("XMP written."); - } else { - System.err.println("Could not find BibEntry " + args[0] + " in " + args[0]); - } - } - } else { - usage(); - } - } - - /** - * Print usage information for the command line tool xmpUtil. - * - * @see XMPUtilMain#main(String[]) - */ - private static void usage() { - System.out.println("Read or write XMP-metadata from or to pdf file."); - System.out.println(""); - System.out.println("Usage:"); - System.out.println("Read from PDF and print as bibtex:"); - System.out.println(" xmpUtil "); - System.out.println("Read from PDF and print raw XMP:"); - System.out.println(" xmpUtil -x "); - System.out - .println("Write the entry in given by to the PDF:"); - System.out.println(" xmpUtil "); - System.out.println("Write all entries in to the PDF:"); - System.out.println(" xmpUtil "); - System.out.println(""); - System.out - .println("To report bugs visit https://issues.jabref.org"); - } - -} diff --git a/src/main/java/org/jabref/cli/XmpUtilMain.java b/src/main/java/org/jabref/cli/XmpUtilMain.java new file mode 100644 index 00000000000..5ff5ffc6a0d --- /dev/null +++ b/src/main/java/org/jabref/cli/XmpUtilMain.java @@ -0,0 +1,129 @@ +package org.jabref.cli; + +import java.io.BufferedReader; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.StringWriter; +import java.nio.file.Paths; +import java.util.List; + +import javax.xml.transform.TransformerException; + +import org.jabref.Globals; +import org.jabref.logic.bibtex.BibEntryWriter; +import org.jabref.logic.bibtex.LatexFieldFormatter; +import org.jabref.logic.importer.ImportFormatPreferences; +import org.jabref.logic.importer.ParserResult; +import org.jabref.logic.importer.fileformat.BibtexParser; +import org.jabref.logic.xmp.XmpPreferences; +import org.jabref.logic.xmp.XmpUtilReader; +import org.jabref.logic.xmp.XmpUtilWriter; +import org.jabref.model.database.BibDatabaseMode; +import org.jabref.model.entry.BibEntry; +import org.jabref.preferences.JabRefPreferences; + +public class XmpUtilMain { + + private static XmpPreferences xmpPreferences; + private static ImportFormatPreferences importFormatPreferences; + + private XmpUtilMain() { + } + + /** + * Reads metadata from pdf and print all included bib entries to the console. + * + * @param filename Filename of the pdf file (.pdf) + */ + private static void readPdfAndPrintBib(String filename) throws IOException { + if (filename.endsWith(".pdf")) { + List entryList = XmpUtilReader.readXmp(filename, xmpPreferences); + + BibEntryWriter bibtexEntryWriter = new BibEntryWriter( + new LatexFieldFormatter(Globals.prefs.getLatexFieldFormatterPreferences()), false); + + for (BibEntry entry : entryList) { + StringWriter writer = new StringWriter(); + bibtexEntryWriter.write(entry, writer, BibDatabaseMode.BIBTEX); + System.out.println(writer.getBuffer()); + } + } else { + System.err.println("Insert a file path (.pdf)"); + } + } + + /** + * Writes all entries included in the bib file to the metadata section of the pdf file. + * + * @param bibFile Filename of the bib file (.bib) + * @param pdfFile Filename of the pdf file (.pdf) + */ + private static void writeBibFileToPdfMetadata(String bibFile, String pdfFile) throws FileNotFoundException, IOException, TransformerException { + if (bibFile.endsWith(".bib") && pdfFile.endsWith(".pdf")) { + try (FileReader reader = new FileReader(bibFile)) { + ParserResult result = new BibtexParser(importFormatPreferences, Globals.getFileUpdateMonitor()).parse(reader); + XmpUtilWriter.writeXmp(Paths.get(pdfFile), result.getDatabase().getEntries(), result.getDatabase(), xmpPreferences); + System.out.println("Metadata sucessfully written to Pdf."); + } + } else { + System.err.println("Insert correct file paths (.bib and .pdf)"); + } + } + + /** + * Print usage information for the console tool xmpUtil. + */ + private static void printMenu() { + System.out.println("---------------------Menu-----------------------"); + System.out.println("(0) Exit"); + System.out.println("(1) Read metadata from PDF and print as bibtex"); + System.out.println("(2) Write entries in bib file to Pdf metadata"); + System.out.println(" To report bugs visit https://issues.jabref.org"); + System.out.println("-------------------------------------------------"); + System.out.print("Choose an option: "); + } + + /** + * The tool is implemented as a console application with a read-evaluate-print cycle. + */ + public static void executeXmpConsoleApplicaton() { + if (Globals.prefs == null) { + Globals.prefs = JabRefPreferences.getInstance(); + } + + xmpPreferences = Globals.prefs.getXMPPreferences(); + importFormatPreferences = Globals.prefs.getImportFormatPreferences(); + + BufferedReader consoleReader = new BufferedReader(new InputStreamReader(System.in)); + + int option = -1; + while (option != 0) { + try { + XmpUtilMain.printMenu(); + option = Integer.parseInt(consoleReader.readLine()); + + if (option == 0) { + break; + } else if (option == 1) { + System.out.print("Insert your filename (.pdf): "); + String filename = consoleReader.readLine().trim(); + XmpUtilMain.readPdfAndPrintBib(filename); + } else if (option == 2) { + System.out.print("Insert your filename (.bib): "); + String bibFile = consoleReader.readLine().trim(); + System.out.print("Insert your filename (.pdf): "); + String pdfFile = consoleReader.readLine().trim(); + XmpUtilMain.writeBibFileToPdfMetadata(bibFile, pdfFile); + } + } catch (IOException | TransformerException e) { + System.err.println(e.getMessage()); + } + } + } + + public static void main(String[] args) { + XmpUtilMain.executeXmpConsoleApplicaton(); + } +} From 437677c0bc9d59f06f63747639418ea5d8326a98 Mon Sep 17 00:00:00 2001 From: Siedlerchr Date: Sat, 24 Feb 2018 11:25:40 +0100 Subject: [PATCH 94/94] Add missing localization for Any file --- src/main/resources/l10n/JabRef_en.properties | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties index cc23c0e41a1..89a57fd22b0 100644 --- a/src/main/resources/l10n/JabRef_en.properties +++ b/src/main/resources/l10n/JabRef_en.properties @@ -2348,3 +2348,5 @@ empty\ BibTeX\ key=empty BibTeX key Your\ Java\ Runtime\ Environment\ is\ located\ at\ %0.=Your Java Runtime Environment is located at %0. Aux\ file=Aux file Group\ containing\ entries\ cited\ in\ a\ given\ TeX\ file=Group containing entries cited in a given TeX file + +Any\ file=Any\ file