# Path: egtlib/parse.py
# class Lines:
#     """
#     Access a text file line by line, with line numbers
#     """
#     def __init__(self, pathname: str, fd: Optional[TextIO] = None):
#         # File name being parsed
#         self.fname = pathname
#         # Current line being parsed
#         self.lineno = 0
#         # Read the file, split in trimmed lines
#         self.lines: List[str]
#         if fd is None:
#             with open(self.fname, "rt") as fd:
#                 self.lines = [x.rstrip() for x in fd]
#         else:
#             self.lines = [x.rstrip() for x in fd]
# 
#     def peek(self) -> Optional[str]:
#         """
#         Return the next line to be parsed, without advancing the cursor.
#         Return None if we are at the end.
#         """
#         if self.lineno < len(self.lines):
#             return self.lines[self.lineno]
#         else:
#             return None
# 
#     def next(self) -> str:
#         """
#         Return the next line to be parsed, advancing the cursor.
#         Raise RuntimeError if we are at the end.
#         """
#         if self.lineno >= len(self.lines):
#             raise RuntimeError("Lines.next() called at the end of the input")
#         res = self.lines[self.lineno]
#         self.lineno += 1
#         return res
# 
#     def rest(self) -> Generator[str, None, None]:
#         """
#         Generate all remaining lines
#         """
#         yield from self.lines[self.lineno:]
# 
#     def discard(self) -> None:
#         """
#         Just advance the cursor to the next line
#         """
#         if self.lineno < len(self.lines):
#             self.lineno += 1
# 
#     def skip_empty_lines(self) -> None:
#         while True:
#             line = self.peek()
#             if line is None:
#                 break
#             if line:
#                 break
#             self.discard()
# 
# Path: egtlib/utils.py
# def format_duration(mins: int, tabular: bool = False):
#     h = mins / 60
#     m = mins % 60
#     if tabular:
#         return "%3dh %02dm" % (h, m)
#     else:
#         if m:
#             return "%dh %dm" % (h, m)
#         else:
#             return "%dh" % h


from typing import Optional, TextIO, List, Dict
from collections import OrderedDict
from .parse import Lines
from .utils import format_duration
import re
import sys
import inspect
        import email
        """
        name = name.lower()
        if hasattr(self, name):
            return getattr(self, name)
        return self._raw.get(name, *args)

    def set(self, name: str, value: str) -> None:
        """
        Set the value of a metadata element
        """
        self._raw[name.lower()] = value

    def unset(self, name: str) -> None:
        """
        Unset the value of a metadata element, if it exists, otherwise does
        nothing
        """
        self._raw.pop(name.lower(), None)

    def set_durations(self, durations: Dict[str, int]) -> None:
        """
        Set the Total: header from the given computed durations
        """
        if len(durations) == 1:
            self.set("total", format_duration(durations[""]))
        else:
            lines = []
            for tag, duration in sorted(durations.items()):
                if not tag:
                    tag = "*"

# Path: egtlib/parse.py
# class Lines:
#     """
#     Access a text file line by line, with line numbers
#     """
#     def __init__(self, pathname: str, fd: Optional[TextIO] = None):
#         # File name being parsed
#         self.fname = pathname
#         # Current line being parsed
#         self.lineno = 0
#         # Read the file, split in trimmed lines
#         self.lines: List[str]
#         if fd is None:
#             with open(self.fname, "rt") as fd:
#                 self.lines = [x.rstrip() for x in fd]
#         else:
#             self.lines = [x.rstrip() for x in fd]
# 
#     def peek(self) -> Optional[str]:
#         """
#         Return the next line to be parsed, without advancing the cursor.
#         Return None if we are at the end.
#         """
#         if self.lineno < len(self.lines):
#             return self.lines[self.lineno]
#         else:
#             return None
# 
#     def next(self) -> str:
#         """
#         Return the next line to be parsed, advancing the cursor.
#         Raise RuntimeError if we are at the end.
#         """
#         if self.lineno >= len(self.lines):
#             raise RuntimeError("Lines.next() called at the end of the input")
#         res = self.lines[self.lineno]
#         self.lineno += 1
#         return res
# 
#     def rest(self) -> Generator[str, None, None]:
#         """
#         Generate all remaining lines
#         """
#         yield from self.lines[self.lineno:]
# 
#     def discard(self) -> None:
#         """
#         Just advance the cursor to the next line
#         """
#         if self.lineno < len(self.lines):
#             self.lineno += 1
# 
#     def skip_empty_lines(self) -> None:
#         while True:
#             line = self.peek()
#             if line is None:
#                 break
#             if line:
#                 break
#             self.discard()
# 
# Path: egtlib/utils.py
# def format_duration(mins: int, tabular: bool = False):
#     h = mins / 60
#     m = mins % 60
#     if tabular:
#         return "%3dh %02dm" % (h, m)
#     else:
#         if m:
#             return "%dh %dm" % (h, m)
#         else:
#             return "%dh" % h


# Path: egtlib/meta.py
from typing import Optional, TextIO, List, Dict
from collections import OrderedDict
from .parse import Lines
from .utils import format_duration
import re
import sys
import inspect
        import email

        """
        name = name.lower()
        if hasattr(self, name):
            return getattr(self, name)
        return self._raw.get(name, *args)

    def set(self, name: str, value: str) -> None:
        """
        Set the value of a metadata element
        """
        self._raw[name.lower()] = value

    def unset(self, name: str) -> None:
        """
        Unset the value of a metadata element, if it exists, otherwise does
        nothing
        """
        self._raw.pop(name.lower(), None)

    def set_durations(self, durations: Dict[str, int]) -> None:
        """
        Set the Total: header from the given computed durations
        """
        if len(durations) == 1:
            self.set("total", format_duration(durations[""]))
        else:
            lines = []
            for tag, duration in sorted(durations.items()):
                if not tag:
                    tag = "*"

                lines.append("{}: {}".format(tag, format_duration(duration)))