# Path: fimfarchive/exceptions.py
# class InvalidStoryError(FimfarchiveError):
#     """
#     Story does not exist.
#     """
# 
# Path: fimfarchive/flavors.py
# class UpdateStatus(Flavor):
#     """
#     Indicates if and how a story has changed.
#     """
#     CREATED = ()
#     REVIVED = ()
#     UPDATED = ()
#     DELETED = ()
# 
# Path: fimfarchive/mappers.py
# class StoryDateMapper(Mapper[Optional[Arrow]]):
#     """
#     Returns the latest timestamp in a story, or None.
#     """
# 
#     def __call__(self, story: Story) -> Optional[Arrow]:
#         try:
#             meta = getattr(story, 'meta', None)
#         except InvalidStoryError:
#             return None
# 
#         if not meta:
#             return None
# 
#         dates = {
#             meta.get('date_modified'),
#         }
# 
#         for chapter in meta.get('chapters') or tuple():
#             dates.add(chapter.get('date_modified'))
# 
#         dates.discard(None)
# 
#         if dates:
#             return max(arrow.get(date) for date in dates)
#         else:
#             return None


from fimfarchive.exceptions import InvalidStoryError
from fimfarchive.flavors import UpdateStatus
from fimfarchive.mappers import StoryDateMapper
    def __init__(self, date_mapper=None):
        """
        Constructor.

        Args:
            date_mapper: Maps a `Story` to its modification date.
        """
        if date_mapper:
            self.date_mapper = date_mapper
        else:
            self.date_mapper = StoryDateMapper()

    def filter_empty(self, story):
        """
        Returns the story if it has chapters, otherwise None.
        """
        meta = getattr(story, 'meta', None)

        if meta and meta.get('chapters'):
            return story
        else:
            return None

    def filter_invalid(self, story):
        """
        Returns the story if it is valid, otherwise None.
        """
        try:
            story.meta
            story.data

# Path: fimfarchive/exceptions.py
# class InvalidStoryError(FimfarchiveError):
#     """
#     Story does not exist.
#     """
# 
# Path: fimfarchive/flavors.py
# class UpdateStatus(Flavor):
#     """
#     Indicates if and how a story has changed.
#     """
#     CREATED = ()
#     REVIVED = ()
#     UPDATED = ()
#     DELETED = ()
# 
# Path: fimfarchive/mappers.py
# class StoryDateMapper(Mapper[Optional[Arrow]]):
#     """
#     Returns the latest timestamp in a story, or None.
#     """
# 
#     def __call__(self, story: Story) -> Optional[Arrow]:
#         try:
#             meta = getattr(story, 'meta', None)
#         except InvalidStoryError:
#             return None
# 
#         if not meta:
#             return None
# 
#         dates = {
#             meta.get('date_modified'),
#         }
# 
#         for chapter in meta.get('chapters') or tuple():
#             dates.add(chapter.get('date_modified'))
# 
#         dates.discard(None)
# 
#         if dates:
#             return max(arrow.get(date) for date in dates)
#         else:
#             return None


# Path: fimfarchive/selectors.py
from fimfarchive.exceptions import InvalidStoryError
from fimfarchive.flavors import UpdateStatus
from fimfarchive.mappers import StoryDateMapper

    def __init__(self, date_mapper=None):
        """
        Constructor.

        Args:
            date_mapper: Maps a `Story` to its modification date.
        """
        if date_mapper:
            self.date_mapper = date_mapper
        else:
            self.date_mapper = StoryDateMapper()

    def filter_empty(self, story):
        """
        Returns the story if it has chapters, otherwise None.
        """
        meta = getattr(story, 'meta', None)

        if meta and meta.get('chapters'):
            return story
        else:
            return None

    def filter_invalid(self, story):
        """
        Returns the story if it is valid, otherwise None.
        """
        try:
            story.meta
            story.data

        except InvalidStoryError: