prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  Create XAPI statements for live video
  ## Feature Request
  
  **Is your feature request related to a problem or unsupported use case? Please describe.**
  
  When a video is a live all the existing XAPI statement are sent like a regular videos. Some events should not be sent and some data can't be computed
  
  **Describe the solution you'd like**
  
  Change the activity-type to `http://id.tincanapi.com/activitytype/webinar`
  Send statement for those events : 
  - initialized
  - play
  - pause
  - interacted
  
  Also, do not send video length info, we can't have it. The completion threshold can not be computed too.
  
  
  </issue>
  <code>
  [start of src/backend/marsha/core/xapi.py]
  1 """XAPI module."""
  2 import re
  3 import uuid
  4 
  5 from django.conf import settings
  6 from django.utils import timezone
  7 from django.utils.translation import to_locale
  8 
  9 import requests
  10 
  11 
  12 class XAPIStatement:
  13     """Object to work on a XAPI Statement."""
  14 
  15     statement = None
  16 
  17     def __init__(self, video, statement, lti_user):
  18         """Compute a valid xapi satement.
  19 
  20         Parameters
  21         ----------
  22         video : Type[.models/videos]
  23             The video object used in the xAPI statement
  24 
  25         statement : dictionary
  26             Statement containing base information to send to the LRS
  27             An example of expected statement:
  28             {
  29                 "verb": {
  30                     "id": "http://adlnet.gov/expapi/verbs/initialized",
  31                     "display": {
  32                         "en-US": "initialized"
  33                     }
  34                 },
  35                 "context": {
  36                     "extensions": {
  37                         "https://w3id.org/xapi/video/extensions/volume": 1,
  38                         "https://w3id.org/xapi/video/extensions/video-playback-size": "640x264",
  39                     }
  40                 }
  41             }
  42 
  43         lti_user : Type[lti.LTIUser]
  44             Object representing data stored in the JWT Token and related to the user authenticated
  45             with LTI
  46 
  47         """
  48         try:
  49             user_id = lti_user.user.get("id")
  50         except AttributeError:
  51             user_id = lti_user.session_id
  52 
  53         homepage = video.playlist.consumer_site.domain
  54 
  55         if re.match(r"^http(s?):\/\/.*", homepage) is None:
  56             homepage = f"http://{homepage}"
  57 
  58         if "id" not in statement:
  59             statement["id"] = str(uuid.uuid4())
  60 
  61         statement["timestamp"] = timezone.now().isoformat()
  62         statement["context"].update(
  63             {"contextActivities": {"category": [{"id": "https://w3id.org/xapi/video"}]}}
  64         )
  65 
  66         statement["actor"] = {
  67             "objectType": "Agent",
  68             "account": {"name": user_id, "homePage": homepage},
  69         }
  70 
  71         statement["object"] = {
  72             "definition": {
  73                 "type": "https://w3id.org/xapi/video/activity-type/video",
  74                 "name": {
  75                     to_locale(settings.LANGUAGE_CODE).replace("_", "-"): video.title
  76                 },
  77             },
  78             "id": "uuid://{id}".format(id=str(video.id)),
  79             "objectType": "Activity",
  80         }
  81 
  82         object_extensions = {}
  83         if lti_user.course.get("school_name") is not None:
  84             object_extensions[
  85                 "https://w3id.org/xapi/acrossx/extensions/school"
  86             ] = lti_user.course["school_name"]
  87 
  88         if lti_user.course.get("course_name") is not None:
  89             object_extensions[
  90                 "http://adlnet.gov/expapi/activities/course"
  91             ] = lti_user.course["course_name"]
  92 
  93         if lti_user.course.get("course_run") is not None:
  94             object_extensions[
  95                 "http://adlnet.gov/expapi/activities/module"
  96             ] = lti_user.course["course_run"]
  97 
  98         if object_extensions:
  99             statement["object"]["definition"]["extensions"] = object_extensions
  100 
  101         self.statement = statement
  102 
  103     def get_statement(self):
  104         """Return the enriched statement."""
  105         return self.statement
  106 
  107 
  108 class XAPI:
  109     """The XAPI object compute statements and send them to a LRS."""
  110 
  111     def __init__(self, url, auth_token, xapi_version="1.0.3"):
  112         """Initialize the XAPI module.
  113 
  114         Parameters
  115         ----------
  116         url: string
  117             The LRS endpoint to fetch
  118 
  119         auth_token: string
  120             The basic_auth token used to authenticate on the LRS
  121 
  122         xapi_version: string
  123             The xAPI version used.
  124 
  125         """
  126         self.url = url
  127         self.auth_token = auth_token
  128         self.xapi_version = xapi_version
  129 
  130     def send(self, xapi_statement):
  131         """Send the statement to a LRS.
  132 
  133         Parameters
  134         ----------
  135         statement : Type[.XAPIStatement]
  136 
  137         """
  138         headers = {
  139             "Authorization": self.auth_token,
  140             "Content-Type": "application/json",
  141             "X-Experience-API-Version": self.xapi_version,
  142         }
  143 
  144         response = requests.post(
  145             self.url, json=xapi_statement.get_statement(), headers=headers
  146         )
  147 
  148         response.raise_for_status()
  149
  [end of src/backend/marsha/core/xapi.py]
  </code>
  
  I need you to solve this issue by generating a single patch file that I can apply directly to this repository using git apply. Please respond with a single patch file in the following format.
  <patch>
  diff --git a/file.py b/file.py
  --- a/file.py
  +++ b/file.py
  @@ -1,27 +1,35 @@
   def euclidean(a, b):
  -    while b:
  -        a, b = b, a % b
  -    return a
  +    if b == 0:
  +        return a
  +    return euclidean(b, a % b)
   
   
   def bresenham(x0, y0, x1, y1):
       points = []
       dx = abs(x1 - x0)
       dy = abs(y1 - y0)
  -    sx = 1 if x0 < x1 else -1
  -    sy = 1 if y0 < y1 else -1
  -    err = dx - dy
  +    x, y = x0, y0
  +    sx = -1 if x0 > x1 else 1
  +    sy = -1 if y0 > y1 else 1
   
  -    while True:
  -        points.append((x0, y0))
  -        if x0 == x1 and y0 == y1:
  -            break
  -        e2 = 2 * err
  -        if e2 > -dy:
  -            err -= dy
  -            x0 += sx
  -        if e2 < dx:
  -            err += dx
  -            y0 += sy
  +    if dx > dy:
  +        err = dx / 2.0
  +        while x != x1:
  +            points.append((x, y))
  +            err -= dy
  +            if err < 0:
  +                y += sy
  +                err += dx
  +            x += sx
  +    else:
  +        err = dy / 2.0
  +        while y != y1:
  +            points.append((x, y))
  +            err -= dx
  +            if err < 0:
  +                x += sx
  +                err += dy
  +            y += sy
  +
  +    points.append((x, y))
       return points
  
  </patch>
golden_diff: diff --git a/src/backend/marsha/core/xapi.py b/src/backend/marsha/core/xapi.py
  --- a/src/backend/marsha/core/xapi.py
  +++ b/src/backend/marsha/core/xapi.py
  @@ -52,6 +52,12 @@
   
           homepage = video.playlist.consumer_site.domain
   
  +        activity_type = "https://w3id.org/xapi/video/activity-type/video"
  +
  +        # When the video is a live we change the activity to webinar
  +        if video.live_state is not None:
  +            activity_type = "http://id.tincanapi.com/activitytype/webinar"
  +
           if re.match(r"^http(s?):\/\/.*", homepage) is None:
               homepage = f"http://{homepage}"
   
  @@ -70,7 +76,7 @@
   
           statement["object"] = {
               "definition": {
  -                "type": "https://w3id.org/xapi/video/activity-type/video",
  +                "type": activity_type,
                   "name": {
                       to_locale(settings.LANGUAGE_CODE).replace("_", "-"): video.title
                   },
  
verification_info: {"golden_diff": "diff --git a/src/backend/marsha/core/xapi.py b/src/backend/marsha/core/xapi.py\n--- a/src/backend/marsha/core/xapi.py\n+++ b/src/backend/marsha/core/xapi.py\n@@ -52,6 +52,12 @@\n \n         homepage = video.playlist.consumer_site.domain\n \n+        activity_type = \"https://w3id.org/xapi/video/activity-type/video\"\n+\n+        # When the video is a live we change the activity to webinar\n+        if video.live_state is not None:\n+            activity_type = \"http://id.tincanapi.com/activitytype/webinar\"\n+\n         if re.match(r\"^http(s?):\\/\\/.*\", homepage) is None:\n             homepage = f\"http://{homepage}\"\n \n@@ -70,7 +76,7 @@\n \n         statement[\"object\"] = {\n             \"definition\": {\n-                \"type\": \"https://w3id.org/xapi/video/activity-type/video\",\n+                \"type\": activity_type,\n                 \"name\": {\n                     to_locale(settings.LANGUAGE_CODE).replace(\"_\", \"-\"): video.title\n                 },\n", "issue": "Create XAPI statements for live video\n## Feature Request\r\n\r\n**Is your feature request related to a problem or unsupported use case? Please describe.**\r\n\r\nWhen a video is a live all the existing XAPI statement are sent like a regular videos. Some events should not be sent and some data can't be computed\r\n\r\n**Describe the solution you'd like**\r\n\r\nChange the activity-type to `http://id.tincanapi.com/activitytype/webinar`\r\nSend statement for those events : \r\n- initialized\r\n- play\r\n- pause\r\n- interacted\r\n\r\nAlso, do not send video length info, we can't have it. The completion threshold can not be computed too.\r\n\n", "before_files": [{"content": "\"\"\"XAPI module.\"\"\"\nimport re\nimport uuid\n\nfrom django.conf import settings\nfrom django.utils import timezone\nfrom django.utils.translation import to_locale\n\nimport requests\n\n\nclass XAPIStatement:\n    \"\"\"Object to work on a XAPI Statement.\"\"\"\n\n    statement = None\n\n    def __init__(self, video, statement, lti_user):\n        \"\"\"Compute a valid xapi satement.\n\n        Parameters\n        ----------\n        video : Type[.models/videos]\n            The video object used in the xAPI statement\n\n        statement : dictionary\n            Statement containing base information to send to the LRS\n            An example of expected statement:\n            {\n                \"verb\": {\n                    \"id\": \"http://adlnet.gov/expapi/verbs/initialized\",\n                    \"display\": {\n                        \"en-US\": \"initialized\"\n                    }\n                },\n                \"context\": {\n                    \"extensions\": {\n                        \"https://w3id.org/xapi/video/extensions/volume\": 1,\n                        \"https://w3id.org/xapi/video/extensions/video-playback-size\": \"640x264\",\n                    }\n                }\n            }\n\n        lti_user : Type[lti.LTIUser]\n            Object representing data stored in the JWT Token and related to the user authenticated\n            with LTI\n\n        \"\"\"\n        try:\n            user_id = lti_user.user.get(\"id\")\n        except AttributeError:\n            user_id = lti_user.session_id\n\n        homepage = video.playlist.consumer_site.domain\n\n        if re.match(r\"^http(s?):\\/\\/.*\", homepage) is None:\n            homepage = f\"http://{homepage}\"\n\n        if \"id\" not in statement:\n            statement[\"id\"] = str(uuid.uuid4())\n\n        statement[\"timestamp\"] = timezone.now().isoformat()\n        statement[\"context\"].update(\n            {\"contextActivities\": {\"category\": [{\"id\": \"https://w3id.org/xapi/video\"}]}}\n        )\n\n        statement[\"actor\"] = {\n            \"objectType\": \"Agent\",\n            \"account\": {\"name\": user_id, \"homePage\": homepage},\n        }\n\n        statement[\"object\"] = {\n            \"definition\": {\n                \"type\": \"https://w3id.org/xapi/video/activity-type/video\",\n                \"name\": {\n                    to_locale(settings.LANGUAGE_CODE).replace(\"_\", \"-\"): video.title\n                },\n            },\n            \"id\": \"uuid://{id}\".format(id=str(video.id)),\n            \"objectType\": \"Activity\",\n        }\n\n        object_extensions = {}\n        if lti_user.course.get(\"school_name\") is not None:\n            object_extensions[\n                \"https://w3id.org/xapi/acrossx/extensions/school\"\n            ] = lti_user.course[\"school_name\"]\n\n        if lti_user.course.get(\"course_name\") is not None:\n            object_extensions[\n                \"http://adlnet.gov/expapi/activities/course\"\n            ] = lti_user.course[\"course_name\"]\n\n        if lti_user.course.get(\"course_run\") is not None:\n            object_extensions[\n                \"http://adlnet.gov/expapi/activities/module\"\n            ] = lti_user.course[\"course_run\"]\n\n        if object_extensions:\n            statement[\"object\"][\"definition\"][\"extensions\"] = object_extensions\n\n        self.statement = statement\n\n    def get_statement(self):\n        \"\"\"Return the enriched statement.\"\"\"\n        return self.statement\n\n\nclass XAPI:\n    \"\"\"The XAPI object compute statements and send them to a LRS.\"\"\"\n\n    def __init__(self, url, auth_token, xapi_version=\"1.0.3\"):\n        \"\"\"Initialize the XAPI module.\n\n        Parameters\n        ----------\n        url: string\n            The LRS endpoint to fetch\n\n        auth_token: string\n            The basic_auth token used to authenticate on the LRS\n\n        xapi_version: string\n            The xAPI version used.\n\n        \"\"\"\n        self.url = url\n        self.auth_token = auth_token\n        self.xapi_version = xapi_version\n\n    def send(self, xapi_statement):\n        \"\"\"Send the statement to a LRS.\n\n        Parameters\n        ----------\n        statement : Type[.XAPIStatement]\n\n        \"\"\"\n        headers = {\n            \"Authorization\": self.auth_token,\n            \"Content-Type\": \"application/json\",\n            \"X-Experience-API-Version\": self.xapi_version,\n        }\n\n        response = requests.post(\n            self.url, json=xapi_statement.get_statement(), headers=headers\n        )\n\n        response.raise_for_status()\n", "path": "src/backend/marsha/core/xapi.py"}]}