prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  Minor inconsistency between study config generation tool and study spec
  
  
  </issue>
  <code>
  [start of nvflare/apis/study_manager_spec.py]
  1 # Copyright (c) 2021-2022, NVIDIA CORPORATION.  All rights reserved.
  2 #
  3 # Licensed under the Apache License, Version 2.0 (the "License");
  4 # you may not use this file except in compliance with the License.
  5 # You may obtain a copy of the License at
  6 #
  7 #     http://www.apache.org/licenses/LICENSE-2.0
  8 #
  9 # Unless required by applicable law or agreed to in writing, software
  10 # distributed under the License is distributed on an "AS IS" BASIS,
  11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 # See the License for the specific language governing permissions and
  13 # limitations under the License.
  14 
  15 import datetime
  16 
  17 
  18 class Study:
  19     def __init__(
  20         self,
  21         name: str,
  22         description: str,
  23         sites: [str],
  24         users: [str],
  25         start_time: datetime.datetime,
  26         end_time: datetime.datetime,
  27         reviewers=None,
  28     ):
  29         self.name = name
  30         self.description = description
  31         self.sites = sites
  32         self.users = users
  33         self.start_time = start_time
  34         self.end_time = end_time
  35         self.reviewers = reviewers
  36         self.create_time = None
  37 
  38 
  39 class StudyManagerSpec(object):
  40     def create_study(self, study: Study) -> Study:
  41         """Create the study object permanently
  42 
  43         The caller must have validated the sites and users of the study.
  44 
  45         Validate the study before saving:
  46         The name of the study must be unique;
  47         Sites and users must be defined;
  48         Start and end time must make sense.
  49 
  50         Args:
  51             study: the caller-provided study info
  52 
  53         Returns: updated study info (e.g. create_time is set)
  54 
  55         """
  56         pass
  57 
  58     def list_studies(self) -> [str]:
  59         """
  60         List names of all defined studies
  61 
  62         Returns: list of study names
  63 
  64         """
  65         pass
  66 
  67     def list_active_studies(self) -> [str]:
  68         """
  69         List names of all active studies (started but not ended)
  70 
  71         Returns: list of study names
  72 
  73         """
  74         pass
  75 
  76     def get_study(self, name: str) -> Study:
  77         """Get the Study object for the specified name.
  78 
  79         Args:
  80             name: unique name of the study
  81 
  82         Returns: the Study object
  83 
  84         """
  85         pass
  86
  [end of nvflare/apis/study_manager_spec.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/nvflare/apis/study_manager_spec.py b/nvflare/apis/study_manager_spec.py
  --- a/nvflare/apis/study_manager_spec.py
  +++ b/nvflare/apis/study_manager_spec.py
  @@ -12,7 +12,11 @@
   # See the License for the specific language governing permissions and
   # limitations under the License.
   
  -import datetime
  +from abc import ABC, abstractmethod
  +from typing import Dict, List
  +from datetime import datetime
  +
  +from .fl_context import FLContext
   
   
   class Study:
  @@ -20,32 +24,35 @@
           self,
           name: str,
           description: str,
  -        sites: [str],
  -        users: [str],
  -        start_time: datetime.datetime,
  -        end_time: datetime.datetime,
  +        contact: str,
  +        participating_clients: List[str],
  +        participating_admins: List[str],
  +        start_date: datetime.date,
  +        end_date: datetime.date,
           reviewers=None,
       ):
           self.name = name
           self.description = description
  -        self.sites = sites
  -        self.users = users
  -        self.start_time = start_time
  -        self.end_time = end_time
  +        self.contact = contact
  +        self.participating_clients = participating_clients
  +        self.participating_admins = participating_admins
  +        self.start_date = start_date
  +        self.end_date = end_date
           self.reviewers = reviewers
  -        self.create_time = None
  +        self.created_at = datetime.utcnow().isoformat()
   
   
  -class StudyManagerSpec(object):
  -    def create_study(self, study: Study) -> Study:
  -        """Create the study object permanently
  +class StudyManagerSpec(ABC):
  +    @abstractmethod
  +    def add_study(self, study: Study, fl_ctx: FLContext) -> Study:
  +        """Add the study object permanently
   
  -        The caller must have validated the sites and users of the study.
  +        The caller must have validated the participating_clients and participating_admins of the study.
   
           Validate the study before saving:
           The name of the study must be unique;
  -        Sites and users must be defined;
  -        Start and end time must make sense.
  +        participating_clients and participating_admins must be defined;
  +        Start and end date must make sense.
   
           Args:
               study: the caller-provided study info
  @@ -55,7 +62,8 @@
           """
           pass
   
  -    def list_studies(self) -> [str]:
  +    @abstractmethod
  +    def list_studies(self, fl_ctx: FLContext) -> List[str]:
           """
           List names of all defined studies
   
  @@ -64,7 +72,8 @@
           """
           pass
   
  -    def list_active_studies(self) -> [str]:
  +    @abstractmethod
  +    def list_active_studies(self, fl_ctx: FLContext) -> List[str]:
           """
           List names of all active studies (started but not ended)
   
  @@ -73,7 +82,8 @@
           """
           pass
   
  -    def get_study(self, name: str) -> Study:
  +    @abstractmethod
  +    def get_study(self, name: str, fl_ctx: FLContext) -> Study:
           """Get the Study object for the specified name.
   
           Args:
  
verification_info: {"golden_diff": "diff --git a/nvflare/apis/study_manager_spec.py b/nvflare/apis/study_manager_spec.py\n--- a/nvflare/apis/study_manager_spec.py\n+++ b/nvflare/apis/study_manager_spec.py\n@@ -12,7 +12,11 @@\n # See the License for the specific language governing permissions and\n # limitations under the License.\n \n-import datetime\n+from abc import ABC, abstractmethod\n+from typing import Dict, List\n+from datetime import datetime\n+\n+from .fl_context import FLContext\n \n \n class Study:\n@@ -20,32 +24,35 @@\n         self,\n         name: str,\n         description: str,\n-        sites: [str],\n-        users: [str],\n-        start_time: datetime.datetime,\n-        end_time: datetime.datetime,\n+        contact: str,\n+        participating_clients: List[str],\n+        participating_admins: List[str],\n+        start_date: datetime.date,\n+        end_date: datetime.date,\n         reviewers=None,\n     ):\n         self.name = name\n         self.description = description\n-        self.sites = sites\n-        self.users = users\n-        self.start_time = start_time\n-        self.end_time = end_time\n+        self.contact = contact\n+        self.participating_clients = participating_clients\n+        self.participating_admins = participating_admins\n+        self.start_date = start_date\n+        self.end_date = end_date\n         self.reviewers = reviewers\n-        self.create_time = None\n+        self.created_at = datetime.utcnow().isoformat()\n \n \n-class StudyManagerSpec(object):\n-    def create_study(self, study: Study) -> Study:\n-        \"\"\"Create the study object permanently\n+class StudyManagerSpec(ABC):\n+    @abstractmethod\n+    def add_study(self, study: Study, fl_ctx: FLContext) -> Study:\n+        \"\"\"Add the study object permanently\n \n-        The caller must have validated the sites and users of the study.\n+        The caller must have validated the participating_clients and participating_admins of the study.\n \n         Validate the study before saving:\n         The name of the study must be unique;\n-        Sites and users must be defined;\n-        Start and end time must make sense.\n+        participating_clients and participating_admins must be defined;\n+        Start and end date must make sense.\n \n         Args:\n             study: the caller-provided study info\n@@ -55,7 +62,8 @@\n         \"\"\"\n         pass\n \n-    def list_studies(self) -> [str]:\n+    @abstractmethod\n+    def list_studies(self, fl_ctx: FLContext) -> List[str]:\n         \"\"\"\n         List names of all defined studies\n \n@@ -64,7 +72,8 @@\n         \"\"\"\n         pass\n \n-    def list_active_studies(self) -> [str]:\n+    @abstractmethod\n+    def list_active_studies(self, fl_ctx: FLContext) -> List[str]:\n         \"\"\"\n         List names of all active studies (started but not ended)\n \n@@ -73,7 +82,8 @@\n         \"\"\"\n         pass\n \n-    def get_study(self, name: str) -> Study:\n+    @abstractmethod\n+    def get_study(self, name: str, fl_ctx: FLContext) -> Study:\n         \"\"\"Get the Study object for the specified name.\n \n         Args:\n", "issue": "Minor inconsistency between study config generation tool and study spec\n\n", "before_files": [{"content": "# Copyright (c) 2021-2022, NVIDIA CORPORATION.  All rights reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport datetime\n\n\nclass Study:\n    def __init__(\n        self,\n        name: str,\n        description: str,\n        sites: [str],\n        users: [str],\n        start_time: datetime.datetime,\n        end_time: datetime.datetime,\n        reviewers=None,\n    ):\n        self.name = name\n        self.description = description\n        self.sites = sites\n        self.users = users\n        self.start_time = start_time\n        self.end_time = end_time\n        self.reviewers = reviewers\n        self.create_time = None\n\n\nclass StudyManagerSpec(object):\n    def create_study(self, study: Study) -> Study:\n        \"\"\"Create the study object permanently\n\n        The caller must have validated the sites and users of the study.\n\n        Validate the study before saving:\n        The name of the study must be unique;\n        Sites and users must be defined;\n        Start and end time must make sense.\n\n        Args:\n            study: the caller-provided study info\n\n        Returns: updated study info (e.g. create_time is set)\n\n        \"\"\"\n        pass\n\n    def list_studies(self) -> [str]:\n        \"\"\"\n        List names of all defined studies\n\n        Returns: list of study names\n\n        \"\"\"\n        pass\n\n    def list_active_studies(self) -> [str]:\n        \"\"\"\n        List names of all active studies (started but not ended)\n\n        Returns: list of study names\n\n        \"\"\"\n        pass\n\n    def get_study(self, name: str) -> Study:\n        \"\"\"Get the Study object for the specified name.\n\n        Args:\n            name: unique name of the study\n\n        Returns: the Study object\n\n        \"\"\"\n        pass\n", "path": "nvflare/apis/study_manager_spec.py"}]}