prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Same explanation for SlidingWindowGeoDataset and RandomWindowGeoDataset
  ## 📚 Documentation
  
  <!-- A clear and concise description of what content in https://docs.rastervision.io/ is an issue.-->
  
  > The SlidingWindowGeoDataset allows reading the scene by sampling random window sizes and locations.
  
  This description is same to explained both SlidingWindowGeoDataset and RandomWindowGeoDataset. This can be found here: https://docs.rastervision.io/en/latest/tutorials/sampling_training_data.html
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `rastervision_core/rastervision/core/data/class_config.py`
  Content:
  ```
  1 from typing import List, Optional, Tuple, Union
  2 
  3 from rastervision.pipeline.config import (Config, register_config, ConfigError,
  4                                           Field, validator)
  5 from rastervision.core.data.utils import color_to_triple, normalize_color
  6 
  7 DEFAULT_NULL_CLASS_NAME = 'null'
  8 DEFAULT_NULL_CLASS_COLOR = 'black'
  9 
  10 
  11 @register_config('class_config')
  12 class ClassConfig(Config):
  13     """Configures the class names that are being predicted."""
  14     names: List[str] = Field(
  15         ...,
  16         description='Names of classes. The i-th class in this list will have '
  17         'class ID = i.')
  18     colors: Optional[List[Union[str, Tuple]]] = Field(
  19         None,
  20         description=
  21         ('Colors used to visualize classes. Can be color strings accepted by '
  22          'matplotlib or RGB tuples. If None, a random color will be auto-generated '
  23          'for each class.'))
  24     null_class: Optional[str] = Field(
  25         None,
  26         description='Optional name of class in `names` to use as the null '
  27         'class. This is used in semantic segmentation to represent the label '
  28         'for imagery pixels that are NODATA or that are missing a label. '
  29         f'If None and the class names include "{DEFAULT_NULL_CLASS_NAME}", '
  30         'it will automatically be used as the null class. If None, and this '
  31         'Config is part of a SemanticSegmentationConfig, a null class will be '
  32         'added automatically.')
  33 
  34     @validator('colors', always=True)
  35     def validate_colors(cls, v: Optional[List[Union[str, Tuple]]],
  36                         values: dict) -> Optional[List[Union[str, Tuple]]]:
  37         """Compare length w/ names. Also auto-generate if not specified."""
  38         class_names = values['names']
  39         class_colors = v
  40         if class_colors is None:
  41             class_colors = [color_to_triple() for _ in class_names]
  42         elif len(class_names) != len(class_colors):
  43             raise ConfigError(f'len(class_names) ({len(class_names)}) != '
  44                               f'len(class_colors) ({len(class_colors)})\n'
  45                               f'class_names: {class_names}\n'
  46                               f'class_colors: {class_colors}')
  47         return class_colors
  48 
  49     @validator('null_class', always=True)
  50     def validate_null_class(cls, v: Optional[str],
  51                             values: dict) -> Optional[str]:
  52         """Check if in names. If 'null' in names, use it as null class."""
  53         names = values['names']
  54         if v is None:
  55             if DEFAULT_NULL_CLASS_NAME in names:
  56                 v = DEFAULT_NULL_CLASS_NAME
  57         else:
  58             if v not in names:
  59                 raise ConfigError(
  60                     f'The null_class, "{v}", must be in list of class names.')
  61 
  62             # edge case
  63             default_null_class_in_names = (DEFAULT_NULL_CLASS_NAME in names)
  64             null_class_neq_default = (v != DEFAULT_NULL_CLASS_NAME)
  65             if default_null_class_in_names and null_class_neq_default:
  66                 raise ConfigError(
  67                     f'"{DEFAULT_NULL_CLASS_NAME}" is in names but the '
  68                     f'specified null_class is something else ("{v}").')
  69         return v
  70 
  71     def get_class_id(self, name: str) -> int:
  72         return self.names.index(name)
  73 
  74     def get_name(self, id: int) -> str:
  75         return self.names[id]
  76 
  77     @property
  78     def null_class_id(self) -> int:
  79         if self.null_class is None:
  80             raise ValueError('null_class is not set')
  81         return self.get_class_id(self.null_class)
  82 
  83     def get_color_to_class_id(self) -> dict:
  84         return dict([(self.colors[i], i) for i in range(len(self.colors))])
  85 
  86     def ensure_null_class(self) -> None:
  87         """Add a null class if one isn't set. This method is idempotent."""
  88         if self.null_class is not None:
  89             return
  90 
  91         null_class_name = DEFAULT_NULL_CLASS_NAME
  92         null_class_color = DEFAULT_NULL_CLASS_COLOR
  93 
  94         # This might seeem redundant given the null class validator above, but
  95         # is actually important. Sometimes there can be multiple ClassConfig
  96         # instances that reference the same list objects for names and colors
  97         # (not clear why this happens). This means that
  98         # each ensure_null_class() call will add to names and colors in each
  99         # copy of ClassConfig but only set its own null_class, which makes this
  100         # method() non-idempotent.
  101         if null_class_name in self.names:
  102             self.null_class = null_class_name
  103             return
  104 
  105         # use random color if default color is already taken
  106         null_class_color_triple = color_to_triple(null_class_color)
  107         all_color_triples = [
  108             color_to_triple(c) if isinstance(c, str) else c
  109             for c in self.colors
  110         ]
  111         if null_class_color_triple in all_color_triples:
  112             null_class_color = color_to_triple()
  113 
  114         self.names.append(null_class_name)
  115         self.colors.append(null_class_color)
  116         self.null_class = null_class_name
  117 
  118     def __len__(self) -> int:
  119         return len(self.names)
  120 
  121     @property
  122     def color_triples(self) -> List[Tuple[float, float, float]]:
  123         color_triples = [normalize_color(c) for c in self.colors]
  124         return color_triples
  125
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/rastervision_core/rastervision/core/data/class_config.py b/rastervision_core/rastervision/core/data/class_config.py
  --- a/rastervision_core/rastervision/core/data/class_config.py
  +++ b/rastervision_core/rastervision/core/data/class_config.py
  @@ -120,5 +120,6 @@
   
       @property
       def color_triples(self) -> List[Tuple[float, float, float]]:
  +        """Class colors in a normalized form."""
           color_triples = [normalize_color(c) for c in self.colors]
           return color_triples
  
verification_info: {"golden_diff": "diff --git a/rastervision_core/rastervision/core/data/class_config.py b/rastervision_core/rastervision/core/data/class_config.py\n--- a/rastervision_core/rastervision/core/data/class_config.py\n+++ b/rastervision_core/rastervision/core/data/class_config.py\n@@ -120,5 +120,6 @@\n \n     @property\n     def color_triples(self) -> List[Tuple[float, float, float]]:\n+        \"\"\"Class colors in a normalized form.\"\"\"\n         color_triples = [normalize_color(c) for c in self.colors]\n         return color_triples\n", "issue": "Same explanation for SlidingWindowGeoDataset and RandomWindowGeoDataset\n## \ud83d\udcda Documentation\r\n\r\n<!-- A clear and concise description of what content in https://docs.rastervision.io/ is an issue.-->\r\n\r\n> The SlidingWindowGeoDataset allows reading the scene by sampling random window sizes and locations.\r\n\r\nThis description is same to explained both SlidingWindowGeoDataset and RandomWindowGeoDataset. This can be found here: https://docs.rastervision.io/en/latest/tutorials/sampling_training_data.html\n", "before_files": [{"content": "from typing import List, Optional, Tuple, Union\n\nfrom rastervision.pipeline.config import (Config, register_config, ConfigError,\n                                          Field, validator)\nfrom rastervision.core.data.utils import color_to_triple, normalize_color\n\nDEFAULT_NULL_CLASS_NAME = 'null'\nDEFAULT_NULL_CLASS_COLOR = 'black'\n\n\n@register_config('class_config')\nclass ClassConfig(Config):\n    \"\"\"Configures the class names that are being predicted.\"\"\"\n    names: List[str] = Field(\n        ...,\n        description='Names of classes. The i-th class in this list will have '\n        'class ID = i.')\n    colors: Optional[List[Union[str, Tuple]]] = Field(\n        None,\n        description=\n        ('Colors used to visualize classes. Can be color strings accepted by '\n         'matplotlib or RGB tuples. If None, a random color will be auto-generated '\n         'for each class.'))\n    null_class: Optional[str] = Field(\n        None,\n        description='Optional name of class in `names` to use as the null '\n        'class. This is used in semantic segmentation to represent the label '\n        'for imagery pixels that are NODATA or that are missing a label. '\n        f'If None and the class names include \"{DEFAULT_NULL_CLASS_NAME}\", '\n        'it will automatically be used as the null class. If None, and this '\n        'Config is part of a SemanticSegmentationConfig, a null class will be '\n        'added automatically.')\n\n    @validator('colors', always=True)\n    def validate_colors(cls, v: Optional[List[Union[str, Tuple]]],\n                        values: dict) -> Optional[List[Union[str, Tuple]]]:\n        \"\"\"Compare length w/ names. Also auto-generate if not specified.\"\"\"\n        class_names = values['names']\n        class_colors = v\n        if class_colors is None:\n            class_colors = [color_to_triple() for _ in class_names]\n        elif len(class_names) != len(class_colors):\n            raise ConfigError(f'len(class_names) ({len(class_names)}) != '\n                              f'len(class_colors) ({len(class_colors)})\\n'\n                              f'class_names: {class_names}\\n'\n                              f'class_colors: {class_colors}')\n        return class_colors\n\n    @validator('null_class', always=True)\n    def validate_null_class(cls, v: Optional[str],\n                            values: dict) -> Optional[str]:\n        \"\"\"Check if in names. If 'null' in names, use it as null class.\"\"\"\n        names = values['names']\n        if v is None:\n            if DEFAULT_NULL_CLASS_NAME in names:\n                v = DEFAULT_NULL_CLASS_NAME\n        else:\n            if v not in names:\n                raise ConfigError(\n                    f'The null_class, \"{v}\", must be in list of class names.')\n\n            # edge case\n            default_null_class_in_names = (DEFAULT_NULL_CLASS_NAME in names)\n            null_class_neq_default = (v != DEFAULT_NULL_CLASS_NAME)\n            if default_null_class_in_names and null_class_neq_default:\n                raise ConfigError(\n                    f'\"{DEFAULT_NULL_CLASS_NAME}\" is in names but the '\n                    f'specified null_class is something else (\"{v}\").')\n        return v\n\n    def get_class_id(self, name: str) -> int:\n        return self.names.index(name)\n\n    def get_name(self, id: int) -> str:\n        return self.names[id]\n\n    @property\n    def null_class_id(self) -> int:\n        if self.null_class is None:\n            raise ValueError('null_class is not set')\n        return self.get_class_id(self.null_class)\n\n    def get_color_to_class_id(self) -> dict:\n        return dict([(self.colors[i], i) for i in range(len(self.colors))])\n\n    def ensure_null_class(self) -> None:\n        \"\"\"Add a null class if one isn't set. This method is idempotent.\"\"\"\n        if self.null_class is not None:\n            return\n\n        null_class_name = DEFAULT_NULL_CLASS_NAME\n        null_class_color = DEFAULT_NULL_CLASS_COLOR\n\n        # This might seeem redundant given the null class validator above, but\n        # is actually important. Sometimes there can be multiple ClassConfig\n        # instances that reference the same list objects for names and colors\n        # (not clear why this happens). This means that\n        # each ensure_null_class() call will add to names and colors in each\n        # copy of ClassConfig but only set its own null_class, which makes this\n        # method() non-idempotent.\n        if null_class_name in self.names:\n            self.null_class = null_class_name\n            return\n\n        # use random color if default color is already taken\n        null_class_color_triple = color_to_triple(null_class_color)\n        all_color_triples = [\n            color_to_triple(c) if isinstance(c, str) else c\n            for c in self.colors\n        ]\n        if null_class_color_triple in all_color_triples:\n            null_class_color = color_to_triple()\n\n        self.names.append(null_class_name)\n        self.colors.append(null_class_color)\n        self.null_class = null_class_name\n\n    def __len__(self) -> int:\n        return len(self.names)\n\n    @property\n    def color_triples(self) -> List[Tuple[float, float, float]]:\n        color_triples = [normalize_color(c) for c in self.colors]\n        return color_triples\n", "path": "rastervision_core/rastervision/core/data/class_config.py"}], "after_files": [{"content": "from typing import List, Optional, Tuple, Union\n\nfrom rastervision.pipeline.config import (Config, register_config, ConfigError,\n                                          Field, validator)\nfrom rastervision.core.data.utils import color_to_triple, normalize_color\n\nDEFAULT_NULL_CLASS_NAME = 'null'\nDEFAULT_NULL_CLASS_COLOR = 'black'\n\n\n@register_config('class_config')\nclass ClassConfig(Config):\n    \"\"\"Configures the class names that are being predicted.\"\"\"\n    names: List[str] = Field(\n        ...,\n        description='Names of classes. The i-th class in this list will have '\n        'class ID = i.')\n    colors: Optional[List[Union[str, Tuple]]] = Field(\n        None,\n        description=\n        ('Colors used to visualize classes. Can be color strings accepted by '\n         'matplotlib or RGB tuples. If None, a random color will be auto-generated '\n         'for each class.'))\n    null_class: Optional[str] = Field(\n        None,\n        description='Optional name of class in `names` to use as the null '\n        'class. This is used in semantic segmentation to represent the label '\n        'for imagery pixels that are NODATA or that are missing a label. '\n        f'If None and the class names include \"{DEFAULT_NULL_CLASS_NAME}\", '\n        'it will automatically be used as the null class. If None, and this '\n        'Config is part of a SemanticSegmentationConfig, a null class will be '\n        'added automatically.')\n\n    @validator('colors', always=True)\n    def validate_colors(cls, v: Optional[List[Union[str, Tuple]]],\n                        values: dict) -> Optional[List[Union[str, Tuple]]]:\n        \"\"\"Compare length w/ names. Also auto-generate if not specified.\"\"\"\n        class_names = values['names']\n        class_colors = v\n        if class_colors is None:\n            class_colors = [color_to_triple() for _ in class_names]\n        elif len(class_names) != len(class_colors):\n            raise ConfigError(f'len(class_names) ({len(class_names)}) != '\n                              f'len(class_colors) ({len(class_colors)})\\n'\n                              f'class_names: {class_names}\\n'\n                              f'class_colors: {class_colors}')\n        return class_colors\n\n    @validator('null_class', always=True)\n    def validate_null_class(cls, v: Optional[str],\n                            values: dict) -> Optional[str]:\n        \"\"\"Check if in names. If 'null' in names, use it as null class.\"\"\"\n        names = values['names']\n        if v is None:\n            if DEFAULT_NULL_CLASS_NAME in names:\n                v = DEFAULT_NULL_CLASS_NAME\n        else:\n            if v not in names:\n                raise ConfigError(\n                    f'The null_class, \"{v}\", must be in list of class names.')\n\n            # edge case\n            default_null_class_in_names = (DEFAULT_NULL_CLASS_NAME in names)\n            null_class_neq_default = (v != DEFAULT_NULL_CLASS_NAME)\n            if default_null_class_in_names and null_class_neq_default:\n                raise ConfigError(\n                    f'\"{DEFAULT_NULL_CLASS_NAME}\" is in names but the '\n                    f'specified null_class is something else (\"{v}\").')\n        return v\n\n    def get_class_id(self, name: str) -> int:\n        return self.names.index(name)\n\n    def get_name(self, id: int) -> str:\n        return self.names[id]\n\n    @property\n    def null_class_id(self) -> int:\n        if self.null_class is None:\n            raise ValueError('null_class is not set')\n        return self.get_class_id(self.null_class)\n\n    def get_color_to_class_id(self) -> dict:\n        return dict([(self.colors[i], i) for i in range(len(self.colors))])\n\n    def ensure_null_class(self) -> None:\n        \"\"\"Add a null class if one isn't set. This method is idempotent.\"\"\"\n        if self.null_class is not None:\n            return\n\n        null_class_name = DEFAULT_NULL_CLASS_NAME\n        null_class_color = DEFAULT_NULL_CLASS_COLOR\n\n        # This might seeem redundant given the null class validator above, but\n        # is actually important. Sometimes there can be multiple ClassConfig\n        # instances that reference the same list objects for names and colors\n        # (not clear why this happens). This means that\n        # each ensure_null_class() call will add to names and colors in each\n        # copy of ClassConfig but only set its own null_class, which makes this\n        # method() non-idempotent.\n        if null_class_name in self.names:\n            self.null_class = null_class_name\n            return\n\n        # use random color if default color is already taken\n        null_class_color_triple = color_to_triple(null_class_color)\n        all_color_triples = [\n            color_to_triple(c) if isinstance(c, str) else c\n            for c in self.colors\n        ]\n        if null_class_color_triple in all_color_triples:\n            null_class_color = color_to_triple()\n\n        self.names.append(null_class_name)\n        self.colors.append(null_class_color)\n        self.null_class = null_class_name\n\n    def __len__(self) -> int:\n        return len(self.names)\n\n    @property\n    def color_triples(self) -> List[Tuple[float, float, float]]:\n        \"\"\"Class colors in a normalized form.\"\"\"\n        color_triples = [normalize_color(c) for c in self.colors]\n        return color_triples\n", "path": "rastervision_core/rastervision/core/data/class_config.py"}]}