# Path: socceraction/data/base.py
# class MissingDataError(Exception):
#     """Exception raised when a field is missing in the input data."""
# 
# Path: socceraction/data/opta/parsers/base.py
# class OptaJSONParser(OptaParser):
#     """Extract data from an Opta JSON data stream.
# 
#     Parameters
#     ----------
#     path : str
#         Path of the data file.
#     """
# 
#     def __init__(self, path: str, **kwargs: Any) -> None:
#         with open(path, 'rt', encoding='utf-8') as fh:
#             self.root = json.load(fh)
# 
# def _get_end_x(qualifiers: Dict[int, Any]) -> Optional[float]:
#     try:
#         # pass
#         if 140 in qualifiers:
#             return float(qualifiers[140])
#         # blocked shot
#         if 146 in qualifiers:
#             return float(qualifiers[146])
#         # passed the goal line
#         if 102 in qualifiers:
#             return float(100)
#         return None
#     except ValueError:
#         return None
# 
# def _get_end_y(qualifiers: Dict[int, Any]) -> Optional[float]:
#     try:
#         # pass
#         if 141 in qualifiers:
#             return float(qualifiers[141])
#         # blocked shot
#         if 147 in qualifiers:
#             return float(qualifiers[147])
#         # passed the goal line
#         if 102 in qualifiers:
#             return float(qualifiers[102])
#         return None
#     except ValueError:
#         return None
# 
# def assertget(dictionary: Dict[str, Any], key: str) -> Any:
#     """Return the value of the item with the specified key.
# 
#     In contrast to the default `get` method, this version will raise an
#     assertion error if the given key is not present in the dict.
# 
#     Parameters
#     ----------
#     dictionary : dict
#         A Python dictionary.
#     key : str
#         A key in the dictionary.
# 
#     Returns
#     -------
#     Any
#         Returns the value for the specified key if the key is in the dictionary.
# 
#     Raises
#     ------
#     AssertionError
#         If the given key could not be found in the dictionary.
#     """
#     value = dictionary.get(key)
#     assert value is not None, 'KeyError: ' + key + ' not found in ' + str(dictionary)
#     return value


from datetime import datetime
from typing import Any, Dict, Tuple
from ...base import MissingDataError
from .base import OptaJSONParser, _get_end_x, _get_end_y, assertget
            available about each event in the data stream.
        """
        f24 = self._get_doc()

        data = assertget(f24, 'data')
        games = assertget(data, 'Games')
        game = assertget(games, 'Game')
        game_attr = assertget(game, '@attributes')
        game_id = int(assertget(game_attr, 'id'))

        events = {}
        for element in assertget(game, 'Event'):
            attr = element['@attributes']
            timestamp = attr['TimeStamp'].get('locale') if attr.get('TimeStamp') else None
            timestamp = datetime.strptime(timestamp, '%Y-%m-%dT%H:%M:%S.%fZ')
            qualifiers = {
                int(q['@attributes']['qualifier_id']): q['@attributes']['value']
                for q in element.get('Q', [])
            }
            start_x = float(assertget(attr, 'x'))
            start_y = float(assertget(attr, 'y'))
            end_x = _get_end_x(qualifiers) or start_x
            end_y = _get_end_y(qualifiers) or start_y

            event_id = int(assertget(attr, 'id'))
            events[(game_id, event_id)] = dict(
                # Fields required by the base schema
                game_id=game_id,
                event_id=event_id,
                period_id=int(assertget(attr, 'period_id')),

# Path: socceraction/data/base.py
# class MissingDataError(Exception):
#     """Exception raised when a field is missing in the input data."""
# 
# Path: socceraction/data/opta/parsers/base.py
# class OptaJSONParser(OptaParser):
#     """Extract data from an Opta JSON data stream.
# 
#     Parameters
#     ----------
#     path : str
#         Path of the data file.
#     """
# 
#     def __init__(self, path: str, **kwargs: Any) -> None:
#         with open(path, 'rt', encoding='utf-8') as fh:
#             self.root = json.load(fh)
# 
# def _get_end_x(qualifiers: Dict[int, Any]) -> Optional[float]:
#     try:
#         # pass
#         if 140 in qualifiers:
#             return float(qualifiers[140])
#         # blocked shot
#         if 146 in qualifiers:
#             return float(qualifiers[146])
#         # passed the goal line
#         if 102 in qualifiers:
#             return float(100)
#         return None
#     except ValueError:
#         return None
# 
# def _get_end_y(qualifiers: Dict[int, Any]) -> Optional[float]:
#     try:
#         # pass
#         if 141 in qualifiers:
#             return float(qualifiers[141])
#         # blocked shot
#         if 147 in qualifiers:
#             return float(qualifiers[147])
#         # passed the goal line
#         if 102 in qualifiers:
#             return float(qualifiers[102])
#         return None
#     except ValueError:
#         return None
# 
# def assertget(dictionary: Dict[str, Any], key: str) -> Any:
#     """Return the value of the item with the specified key.
# 
#     In contrast to the default `get` method, this version will raise an
#     assertion error if the given key is not present in the dict.
# 
#     Parameters
#     ----------
#     dictionary : dict
#         A Python dictionary.
#     key : str
#         A key in the dictionary.
# 
#     Returns
#     -------
#     Any
#         Returns the value for the specified key if the key is in the dictionary.
# 
#     Raises
#     ------
#     AssertionError
#         If the given key could not be found in the dictionary.
#     """
#     value = dictionary.get(key)
#     assert value is not None, 'KeyError: ' + key + ' not found in ' + str(dictionary)
#     return value


# Path: socceraction/data/opta/parsers/f24_json.py
from datetime import datetime
from typing import Any, Dict, Tuple
from ...base import MissingDataError
from .base import OptaJSONParser, _get_end_x, _get_end_y, assertget

            available about each event in the data stream.
        """
        f24 = self._get_doc()

        data = assertget(f24, 'data')
        games = assertget(data, 'Games')
        game = assertget(games, 'Game')
        game_attr = assertget(game, '@attributes')
        game_id = int(assertget(game_attr, 'id'))

        events = {}
        for element in assertget(game, 'Event'):
            attr = element['@attributes']
            timestamp = attr['TimeStamp'].get('locale') if attr.get('TimeStamp') else None
            timestamp = datetime.strptime(timestamp, '%Y-%m-%dT%H:%M:%S.%fZ')
            qualifiers = {
                int(q['@attributes']['qualifier_id']): q['@attributes']['value']
                for q in element.get('Q', [])
            }
            start_x = float(assertget(attr, 'x'))
            start_y = float(assertget(attr, 'y'))
            end_x = _get_end_x(qualifiers) or start_x
            end_y = _get_end_y(qualifiers) or start_y

            event_id = int(assertget(attr, 'id'))
            events[(game_id, event_id)] = dict(
                # Fields required by the base schema
                game_id=game_id,
                event_id=event_id,
                period_id=int(assertget(attr, 'period_id')),

                team_id=int(assertget(attr, 'team_id')),